◐ Shell
clean mode source ↗

Issue 40792: Make PyNumber_Index() always returning an exact int instance

Currently PyNumber_Index() can return something that's an instance of a strict subclass of int. For example PyNumber_Index(Py_True) returns Py_True. The same for operator.index():

>>> import operator
>>> operator.index(True)
True

The proposed PR makes it always return an int.

To avoid possible overhead for creating temporary integer object, added private function _PyNumber_Index() with the past behavior. It can be used for short-living integer objects which for which only its value will be used, but not its methods. For example in the implementation of PyLong_AsLong() and similar functions.

See also issue17576.
The behaviour change for range sounds reasonable to me.

Just to make sure I understand the impact of the change:

- For Python < 3.10, we sometimes convert the range inputs to Python ints, and sometimes don't. For example, a start value of `np.int64(5)` would be converted, but a value of `True` would not be.

- With this change, we'd always convert a non-int to an int, so both `np.int64(1)` and `True` would be converted to a `1` of exact type int.

IMO this is fine; the new behaviour seems more consistent than the old.

>>> import numpy as np
>>> start = np.int64(2)
>>> range(start, 5).start is start
False
>>> start = True
>>> range(start, 5).start is start
True