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