Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2389,10 +2389,8 @@ left undefined.

.. note::

In order to have a coherent integer type class, when :meth:`__index__` is
defined :meth:`__int__` should also be defined, and both should return
the same value.

If :meth:`__index__` is defined and not :meth:`__int__`, :meth:`__int__`
automatically defaults to :meth:`__index__`.

.. method:: object.__round__(self, [,ndigits])
object.__trunc__(self)
Expand Down
9 changes: 8 additions & 1 deletion Lib/test/test_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def test_int_subclass_with_index(self):
# subclasses. See issue #17576.
class MyInt(int):
def __index__(self):
return int(self) + 1
return self + 1

my_int = MyInt(7)
direct_index = my_int.__index__()
Expand Down Expand Up @@ -89,6 +89,13 @@ def __index__(self):
n = operator.index(bad_int)
self.assertEqual(n, 0)

def test_int_defaults_to_index(self):
class Test:
def __index__(self):
return 4

self.assertEqual(int(Test()), 4)


class SeqTestCase:
# This test case isn't run directly. It just defines common tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:meth:`__int__` defaults to :meth:`__index__` when only the latter is
defined. Patch contributed by Rémi Lapeyre.
13 changes: 11 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5393,8 +5393,9 @@ PyType_Ready(PyTypeObject *type)
}
}

/* Hack for tp_hash and __hash__.
If after all that, tp_hash is still NULL, and __hash__ is not in
/* Set default methods */

/* If after all that, tp_hash is still NULL, and __hash__ is not in
tp_dict, set tp_hash to PyObject_HashNotImplemented and
tp_dict['__hash__'] equal to None.
This signals that __hash__ is not inherited.
Expand Down Expand Up @@ -5435,6 +5436,14 @@ PyType_Ready(PyTypeObject *type)
goto error;
}

/* If __index__ is defined but not __int__, make it default to __index__.
Don't touch __float__ and __complex__ as there could be some loss of
precision.
*/
if (type->tp_as_number != NULL && type->tp_as_number->nb_int == NULL) {
type->tp_as_number->nb_int = type->tp_as_number->nb_index;
}

/* All done -- set the ready flag */
type->tp_flags =
(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
Expand Down