diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index c0dab83977e427..9c216f80e29bee 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -122,7 +122,7 @@ The mathematical and bitwise operations are the most numerous: .. function:: index(a) __index__(a) - Return *a* converted to an integer. Equivalent to ``a.__index__()``. + Return *a* converted to an integer. Equivalent to ``int(type(a).__index__(a))``. .. versionchanged:: 3.10 The result always has exact type :class:`int`. Previously, the result diff --git a/Lib/operator.py b/Lib/operator.py index 1b765522f85949..d330c63ef6eba5 100644 --- a/Lib/operator.py +++ b/Lib/operator.py @@ -93,8 +93,11 @@ def floordiv(a, b): return a // b def index(a): - "Same as a.__index__()." - return a.__index__() + "Same as int(type(a).__index__(a))." + if hasattr(type(a), '__index__'): + return int(a) + raise TypeError(f"'{type(a).__name__}' object cannot be " + "interpreted as an integer") def inv(a): "Same as ~a." diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index 1f89986c777ced..1458268d3e1a38 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -570,6 +570,34 @@ def __index__(self): with self.assertRaises((AttributeError, TypeError)): operator.index(None) + self.assertRaises(TypeError, operator.index) + self.assertRaises(TypeError, operator.index, 1, 1) + self.assertEqual(operator.index(True), 1) + self.assertRaises(TypeError, operator.index, '42') + self.assertRaises(TypeError, operator.index, 42.0) + x = X() + x.__index__ = lambda: 1729 + self.assertEqual(operator.index(x), 1) + class F: + def __index__(self): + return 42.0 + self.assertRaises(TypeError, operator.index, F()) + class I(int): + def __index__(): + return 42 + i = I() + self.assertIs(operator.index(i), int(i)) + class D: + def __index__(self): + return I(42) + with self.assertWarns(DeprecationWarning): + self.assertEqual(operator.index(D()), 42) + class S: + @staticmethod + def __index__(): + return 42 + self.assertEqual(operator.index(S()), 42) + def test_not_(self): operator = self.module class C: diff --git a/Misc/NEWS.d/next/Library/2026-04-03-01-53-16.gh-issue-62912.DHA_yk.rst b/Misc/NEWS.d/next/Library/2026-04-03-01-53-16.gh-issue-62912.DHA_yk.rst new file mode 100644 index 00000000000000..1fd1afcf1bc5ff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-03-01-53-16.gh-issue-62912.DHA_yk.rst @@ -0,0 +1,2 @@ +Correct pure-Python version of the :func:`operator.index` to behave like the +C version. Patch by Sergey B Kirpichev.