Skip to content
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.2.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Bug fixes
- :meth:`DataFrame.__dataframe__` was producing incorrect data buffers when the column's type was nullable boolean (:issue:`55332`)
- :meth:`DataFrame.__dataframe__` was showing bytemask instead of bitmask for ``'string[pyarrow]'`` validity buffer (:issue:`57762`)
- :meth:`DataFrame.__dataframe__` was showing non-null validity buffer (instead of ``None``) ``'string[pyarrow]'`` without missing values (:issue:`57761`)
- :meth:`DataFrame.__getitem__` was returning modified columns when called with ``slice`` on Python 3.12 (:issue:`57500`)

.. ---------------------------------------------------------------------------
.. _whatsnew_222.other:
Expand Down
9 changes: 5 additions & 4 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -3849,6 +3849,11 @@ def __getitem__(self, key):
key = lib.item_from_zerodim(key)
key = com.apply_if_callable(key, self)

# Do we have a slicer (on rows)?
# As of Python 3.12, slice is hashable so check it first
if isinstance(key, slice):
return self._getitem_slice(key)

if is_hashable(key) and not is_iterator(key):
# is_iterator to exclude generator e.g. test_getitem_listlike
# shortcut if the key is in columns
Expand All @@ -3865,10 +3870,6 @@ def __getitem__(self, key):
elif is_mi and self.columns.is_unique and key in self.columns:
return self._getitem_multilevel(key)

# Do we have a slicer (on rows)?
if isinstance(key, slice):
return self._getitem_slice(key)

# Do we have a (boolean) DataFrame?
if isinstance(key, DataFrame):
return self.where(key)
Expand Down
10 changes: 10 additions & 0 deletions pandas/tests/frame/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,16 @@ def test_loc_setitem_boolean_mask_allfalse(self):
result.loc[result.b.isna(), "a"] = result.a.copy()
tm.assert_frame_equal(result, df)

def test_getitem_slice_empty(self):
df = DataFrame([[1]], columns=MultiIndex.from_product([["A"], ["a"]]))
result = df[:]

expected = DataFrame([[1]], columns=MultiIndex.from_product([["A"], ["a"]]))

tm.assert_frame_equal(result, expected)
# Ensure df[:] returns a view of df, not the same object
assert result is not df

def test_getitem_fancy_slice_integers_step(self):
df = DataFrame(np.random.default_rng(2).standard_normal((10, 5)))

Expand Down