Skip to content

Commit 3d135f3

Browse files
REF: avoid mutating Series._values directly in setitem but defer to Manager method (pandas-dev#41879)
1 parent eaee348 commit 3d135f3

File tree

4 files changed

+29
-3
lines changed

4 files changed

+29
-3
lines changed

pandas/core/internals/array_manager.py

+8
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,14 @@ def apply(self, func, **kwargs):
12811281
return type(self)([new_array], self._axes)
12821282

12831283
def setitem(self, indexer, value):
1284+
"""
1285+
Set values with indexer.
1286+
1287+
For SingleArrayManager, this backs s[indexer] = value
1288+
1289+
See `setitem_inplace` for a version that works inplace and doesn't
1290+
return a new Manager.
1291+
"""
12841292
return self.apply_with_block("setitem", indexer=indexer, value=value)
12851293

12861294
def idelete(self, indexer) -> SingleArrayManager:

pandas/core/internals/base.py

+12
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ def array(self):
159159
"""
160160
return self.arrays[0] # type: ignore[attr-defined]
161161

162+
def setitem_inplace(self, indexer, value) -> None:
163+
"""
164+
Set values with indexer.
165+
166+
For Single[Block/Array]Manager, this backs s[indexer] = value
167+
168+
This is an inplace version of `setitem()`, mutating the manager/values
169+
in place, not returning a new Manager (and Block), and thus never changing
170+
the dtype.
171+
"""
172+
self.array[indexer] = value
173+
162174

163175
def interleaved_dtype(dtypes: list[DtypeObj]) -> DtypeObj | None:
164176
"""

pandas/core/internals/managers.py

+5
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,11 @@ def where(self: T, other, cond, align: bool, errors: str) -> T:
352352
)
353353

354354
def setitem(self: T, indexer, value) -> T:
355+
"""
356+
Set values with indexer.
357+
358+
For SingleBlockManager, this backs s[indexer] = value
359+
"""
355360
return self.apply("setitem", indexer=indexer, value=value)
356361

357362
def putmask(self, mask, new, align: bool = True):

pandas/core/series.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,6 @@ def __setitem__(self, key, value) -> None:
10611061
try:
10621062
self._set_with_engine(key, value)
10631063
except (KeyError, ValueError):
1064-
values = self._values
10651064
if is_integer(key) and self.index.inferred_type != "integer":
10661065
# positional setter
10671066
if not self.index._should_fallback_to_positional:
@@ -1075,7 +1074,8 @@ def __setitem__(self, key, value) -> None:
10751074
FutureWarning,
10761075
stacklevel=2,
10771076
)
1078-
values[key] = value
1077+
# this is equivalent to self._values[key] = value
1078+
self._mgr.setitem_inplace(key, value)
10791079
else:
10801080
# GH#12862 adding a new key to the Series
10811081
self.loc[key] = value
@@ -1107,7 +1107,8 @@ def _set_with_engine(self, key, value) -> None:
11071107
# error: Argument 1 to "validate_numeric_casting" has incompatible type
11081108
# "Union[dtype, ExtensionDtype]"; expected "dtype"
11091109
validate_numeric_casting(self.dtype, value) # type: ignore[arg-type]
1110-
self._values[loc] = value
1110+
# this is equivalent to self._values[key] = value
1111+
self._mgr.setitem_inplace(loc, value)
11111112

11121113
def _set_with(self, key, value):
11131114
# other: fancy integer or otherwise

0 commit comments

Comments
 (0)