You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BUG: number.__int__ and int(number) are not the same #9972
As worked around in #9181, we have two implementation of every number.__int__, one in scalarmath (int), and one in scalartypes (__int__).
This happens because after calling PyType_Ready, we reassign tp_number, but the __int__ slot wrapper has already been created.
It's super misleading that this is the case, and exposes cpython implementation details.
It seems to me it would be safer to not set __int__ at all until we fix this, rather than having two possibly different implementation to trap the end user
Not only because of reassignment after PyType_Ready, also because of CPython quirks. For example, this code has different paths due to CPython not inheriting nb_int but inheriting __int__ via mro lookup.
It successfully calls int(a) via int_new which eventually calls int_from_string in cpython2.7 abstract.c since PyStringArrType_Type.tp_from_number.nb_int is NULL.
It fails with a.__int__() since type(a).mro() hits numpy.generic which has gentype_int as its nb_int
>>> a = np.array(['100'])[0]
>>> int(a)
100
>>> a.__int__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: don't know how to convert scalar number to int
Just to clarify - PyStringArrType_Type.tp_as_number is not overwritten after PyType_Ready in addscalar_math, only the numeric types are overwritten, so this is purely a CPython method lookup quirk
Right, but it also means that our implementation right now is incorrect. int(x) is also supposed to try __trunc__ if __int__ doesn't exist. #10042 fixes that.
Activity
mattip commentedon Nov 15, 2017
Not only because of reassignment after
PyType_Ready, also because of CPython quirks. For example, this code has different paths due to CPython not inheritingnb_intbut inheriting__int__via mro lookup.It successfully calls
int(a)viaint_newwhich eventually callsint_from_stringin cpython2.7 abstract.c sincePyStringArrType_Type.tp_from_number.nb_intisNULL.It fails with
a.__int__()sincetype(a).mro()hitsnumpy.genericwhich hasgentype_intas itsnb_intmattip commentedon Nov 15, 2017
Just to clarify -
PyStringArrType_Type.tp_as_numberis not overwritten afterPyType_Readyinaddscalar_math, only the numeric types are overwritten, so this is purely a CPython method lookup quirkeric-wieser commentedon Nov 17, 2017
I'm wondering if the culprit is
ndarray.__int__, which for some reason doesn't fall back onPyNumber_Int, instead trying to call the members directly.mattip commentedon Nov 17, 2017
That would add another layer of abstraction, slowing down the conversion for the 99% of the cases when a
nb_intexistseric-wieser commentedon Nov 17, 2017
Right, but it also means that our implementation right now is incorrect.
int(x)is also supposed to try__trunc__if__int__doesn't exist. #10042 fixes that.eric-wieser commentedon Nov 17, 2017
Another example:
mattip commentedon Feb 20, 2019
#10042 fixed these. These now work
and
bsipocz commentedon Oct 15, 2019
It looks like everything works here now. Can this be closed @mattip?
mattip commentedon Dec 8, 2019
Closing. Please reopen if more discrepancies appear