Skip to content

Commit 0e1a6c1

Browse files
authored
CLN: BlockManager.get_slice require only slice arg (#40262)
1 parent 75ad9bc commit 0e1a6c1

File tree

8 files changed

+72
-13
lines changed

8 files changed

+72
-13
lines changed

pandas/core/indexes/base.py

+7
Original file line numberDiff line numberDiff line change
@@ -4551,6 +4551,13 @@ def __getitem__(self, key):
45514551
else:
45524552
return result
45534553

4554+
def _getitem_slice(self: _IndexT, slobj: slice) -> _IndexT:
4555+
"""
4556+
Fastpath for __getitem__ when we know we have a slice.
4557+
"""
4558+
res = self._data[slobj]
4559+
return type(self)._simple_new(res, name=self._name)
4560+
45544561
@final
45554562
def _can_hold_identifiers_and_holds_name(self, name) -> bool:
45564563
"""

pandas/core/indexes/multi.py

+18
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,24 @@ def __getitem__(self, key):
21012101
verify_integrity=False,
21022102
)
21032103

2104+
def _getitem_slice(self: MultiIndex, slobj: slice) -> MultiIndex:
2105+
"""
2106+
Fastpath for __getitem__ when we know we have a slice.
2107+
"""
2108+
sortorder = None
2109+
if slobj.step is None or slobj.step > 0:
2110+
sortorder = self.sortorder
2111+
2112+
new_codes = [level_codes[slobj] for level_codes in self.codes]
2113+
2114+
return type(self)(
2115+
levels=self.levels,
2116+
codes=new_codes,
2117+
names=self._names,
2118+
sortorder=sortorder,
2119+
verify_integrity=False,
2120+
)
2121+
21042122
@Appender(_index_shared_docs["take"] % _index_doc_kwargs)
21052123
def take(
21062124
self: MultiIndex, indices, axis=0, allow_fill=True, fill_value=None, **kwargs

pandas/core/indexes/range.py

+7
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,13 @@ def __getitem__(self, key):
817817
# fall back to Int64Index
818818
return super().__getitem__(key)
819819

820+
def _getitem_slice(self: RangeIndex, slobj: slice) -> RangeIndex:
821+
"""
822+
Fastpath for __getitem__ when we know we have a slice.
823+
"""
824+
res = self._range[slobj]
825+
return type(self)._simple_new(res, name=self._name)
826+
820827
@unpack_zerodim_and_defer("__floordiv__")
821828
def __floordiv__(self, other):
822829

pandas/core/internals/array_manager.py

+2
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,8 @@ def get_slice(self, slobj: slice, axis: int = 0) -> ArrayManager:
788788

789789
return type(self)(arrays, new_axes, verify_integrity=False)
790790

791+
getitem_mgr = get_slice
792+
791793
def fast_xs(self, loc: int) -> ArrayLike:
792794
"""
793795
Return the array corresponding to `frame.iloc[loc]`.

pandas/core/internals/blocks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ def getitem_block(self, slicer, new_mgr_locs=None) -> Block:
368368
"""
369369
Perform __getitem__-like, return result as block.
370370
371-
As of now, only supports slices that preserve dimensionality.
371+
Only supports slices that preserve dimensionality.
372372
"""
373373
if new_mgr_locs is None:
374374
axis0_slicer = slicer[0] if isinstance(slicer, tuple) else slicer

pandas/core/internals/managers.py

+25-10
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,7 @@ def _combine(
802802
return type(self).from_blocks(new_blocks, axes)
803803

804804
def get_slice(self, slobj: slice, axis: int = 0) -> BlockManager:
805+
assert isinstance(slobj, slice), type(slobj)
805806

806807
if axis == 0:
807808
new_blocks = self._slice_take_blocks_ax0(slobj)
@@ -812,7 +813,7 @@ def get_slice(self, slobj: slice, axis: int = 0) -> BlockManager:
812813
raise IndexError("Requested axis not found in manager")
813814

814815
new_axes = list(self.axes)
815-
new_axes[axis] = new_axes[axis][slobj]
816+
new_axes[axis] = new_axes[axis]._getitem_slice(slobj)
816817

817818
return type(self)._simple_new(tuple(new_blocks), new_axes)
818819

@@ -1201,15 +1202,17 @@ def value_getitem(placement):
12011202
# Newly created block's dtype may already be present.
12021203
self._known_consolidated = False
12031204

1204-
def insert(self, loc: int, item: Hashable, value, allow_duplicates: bool = False):
1205+
def insert(
1206+
self, loc: int, item: Hashable, value: ArrayLike, allow_duplicates: bool = False
1207+
):
12051208
"""
12061209
Insert item at selected position.
12071210
12081211
Parameters
12091212
----------
12101213
loc : int
12111214
item : hashable
1212-
value : array_like
1215+
value : np.ndarray or ExtensionArray
12131216
allow_duplicates: bool
12141217
If False, trying to insert non-unique item will raise
12151218
@@ -1226,11 +1229,9 @@ def insert(self, loc: int, item: Hashable, value, allow_duplicates: bool = False
12261229

12271230
if value.ndim == 2:
12281231
value = value.T
1229-
elif value.ndim == self.ndim - 1:
1230-
# TODO(EA2D): special case not needed with 2D EAs
1231-
value = ensure_block_shape(value, ndim=2)
1232+
else:
1233+
value = ensure_block_shape(value, ndim=self.ndim)
12321234

1233-
# TODO: type value as ArrayLike
12341235
block = new_block(values=value, ndim=self.ndim, placement=slice(loc, loc + 1))
12351236

12361237
for blkno, count in _fast_count_smallints(self.blknos[loc:]):
@@ -1367,6 +1368,7 @@ def _slice_take_blocks_ax0(
13671368
# TODO(EA2D): special casing unnecessary with 2D EAs
13681369
if sllen == 0:
13691370
return []
1371+
# TODO: tests all have isinstance(slobj, slice), other possibilities?
13701372
return [blk.getitem_block(slobj, new_mgr_locs=slice(0, sllen))]
13711373
elif not allow_fill or self.ndim == 1:
13721374
if allow_fill and fill_value is None:
@@ -1376,9 +1378,11 @@ def _slice_take_blocks_ax0(
13761378
# GH#33597 slice instead of take, so we get
13771379
# views instead of copies
13781380
blocks = [
1379-
blk.getitem_block([ml], new_mgr_locs=i)
1381+
blk.getitem_block(slice(ml, ml + 1), new_mgr_locs=i)
13801382
for i, ml in enumerate(slobj)
13811383
]
1384+
# We have
1385+
# all(np.shares_memory(nb.values, blk.values) for nb in blocks)
13821386
return blocks
13831387
else:
13841388
return [
@@ -1440,7 +1444,8 @@ def _slice_take_blocks_ax0(
14401444
# GH#33597 slice instead of take, so we get
14411445
# views instead of copies
14421446
for i, ml in zip(taker, mgr_locs):
1443-
nb = blk.getitem_block([i], new_mgr_locs=ml)
1447+
nb = blk.getitem_block(slice(i, i + 1), new_mgr_locs=ml)
1448+
# We have np.shares_memory(nb.values, blk.values)
14441449
blocks.append(nb)
14451450
else:
14461451
nb = blk.take_nd(taker, axis=0, new_mgr_locs=mgr_locs)
@@ -1604,14 +1609,23 @@ def _blklocs(self):
16041609
""" compat with BlockManager """
16051610
return None
16061611

1612+
def getitem_mgr(self, indexer) -> SingleBlockManager:
1613+
# similar to get_slice, but not restricted to slice indexer
1614+
blk = self._block
1615+
array = blk._slice(indexer)
1616+
block = blk.make_block_same_class(array, placement=slice(0, len(array)))
1617+
return type(self)(block, self.index[indexer])
1618+
16071619
def get_slice(self, slobj: slice, axis: int = 0) -> SingleBlockManager:
1620+
assert isinstance(slobj, slice), type(slobj)
16081621
if axis >= self.ndim:
16091622
raise IndexError("Requested axis not found in manager")
16101623

16111624
blk = self._block
16121625
array = blk._slice(slobj)
16131626
block = blk.make_block_same_class(array, placement=slice(0, len(array)))
1614-
return type(self)(block, self.index[slobj])
1627+
new_index = self.index._getitem_slice(slobj)
1628+
return type(self)(block, new_index)
16151629

16161630
@property
16171631
def index(self) -> Index:
@@ -1975,6 +1989,7 @@ def _preprocess_slice_or_indexer(slice_or_indexer, length: int, allow_fill: bool
19751989
):
19761990
return "mask", slice_or_indexer, slice_or_indexer.sum()
19771991
else:
1992+
# TODO: np.intp?
19781993
indexer = np.asanyarray(slice_or_indexer, dtype=np.int64)
19791994
if not allow_fill:
19801995
indexer = maybe_convert_indices(indexer, length)

pandas/core/series.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ def _get_values_tuple(self, key):
983983

984984
def _get_values(self, indexer):
985985
try:
986-
return self._constructor(self._mgr.get_slice(indexer)).__finalize__(self)
986+
new_mgr = self._mgr.getitem_mgr(indexer)
987+
return self._constructor(new_mgr).__finalize__(self)
987988
except ValueError:
988989
# mpl compat if we look up e.g. ser[:, np.newaxis];
989990
# see tests.series.timeseries.test_mpl_compat_hack

pandas/tests/internals/test_internals.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,16 @@ def assert_slice_ok(mgr, axis, slobj):
823823
slobj = np.concatenate(
824824
[slobj, np.zeros(len(ax) - len(slobj), dtype=bool)]
825825
)
826-
sliced = mgr.get_slice(slobj, axis=axis)
826+
827+
if isinstance(slobj, slice):
828+
sliced = mgr.get_slice(slobj, axis=axis)
829+
elif mgr.ndim == 1 and axis == 0:
830+
sliced = mgr.getitem_mgr(slobj)
831+
else:
832+
# BlockManager doesnt support non-slice, SingleBlockManager
833+
# doesnt support axis > 0
834+
return
835+
827836
mat_slobj = (slice(None),) * axis + (slobj,)
828837
tm.assert_numpy_array_equal(
829838
mat[mat_slobj], sliced.as_array(), check_dtype=False

0 commit comments

Comments
 (0)