diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 950082f9281c5..6313cdee1fd48 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -157,7 +157,7 @@ Strings Interval ^^^^^^^^ -- +- Bug in :meth:`DataFrame.iloc` raising error when indexing with a ``NamedTuple`` (:issue:`48188`) - Indexing diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 2e7a237406ca5..8185dd0ea9ce9 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1177,7 +1177,11 @@ def _check_deprecated_callable_usage(self, key: Any, maybe_callable: T) -> T: @final def __getitem__(self, key): check_dict_or_set_indexers(key) - if type(key) is tuple: + if ( + type(key) is tuple + or isinstance(key, tuple) + and isinstance(self, _iLocIndexer) + ): key = tuple(list(x) if is_iterator(x) else x for x in key) key = tuple(com.apply_if_callable(x, self.obj) for x in key) if self._is_scalar_access(key): diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 0373c15d15272..05348aaaa80df 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1473,6 +1473,17 @@ def test_loc_named_tuple_for_midx(self): ) tm.assert_frame_equal(result, expected) + def test_iloc_tuple_subclass(self, float_frame): + # GH#48188 + indexer_tuple = namedtuple("Indexer", ["row", "col"]) + idx = indexer_tuple(row=1, col=2) + assert float_frame.iloc[idx] == float_frame.iloc[1, 2] + + idx = indexer_tuple(row=[1, 2], col=[1, 2]) + result = float_frame.iloc[idx] + expected = float_frame.iloc[[1, 2], [1, 2]] + tm.assert_frame_equal(result, expected) + @pytest.mark.parametrize("indexer", [["a"], "a"]) @pytest.mark.parametrize("col", [{}, {"b": 1}]) def test_set_2d_casting_date_to_int(self, col, indexer):