Why is numpy.int32 not recognized as an int type
Why should numpy.int32
descend from int
? int
is a specific class. It is one way of representing integers. That doesn't mean that every class that represents integers should descend from int
. numpy.int32
has different semantics and different methods - for example, it has most of the functionality needed to operate like a 0-dimensional array - and inheriting from int
isn't particularly useful for implementing numpy.int32
.
On some builds of Python 2 (Windows only?), numpy.int32
actually will descend from int
(which is also 32-bit on those builds), but I believe this design decision dates back to a time when int
performed wraparound arithmetic like numpy.int32
instead of promoting to long
on overflow, and when operator.index
didn't exist. It was a more reasonable decision back then.
As for how to treat numpy.int32
like int
, numbers.Integral
does a sort of okay job, but the implementation relies on people explicitly register
-ing their classes with numbers.Integral
, and people often don't think to do that. NumPy didn't add the register
calls until 2014, 6 years after numbers.Integral
was introduced. Similar libraries like SymPy still don't have the calls.
I find operator.index
to be a better check:
try:
real_int = operator.index(some_intlike_thing)
except TypeError:
# Not intlike.
do_something_about_that()
operator.index
is the hook an int-like class has to implement to make its instances usable as a sequence index. It's a stricter check than int(x)
, which would accept 3.5
and '3'
. Since there's a concrete, easily noticeable impact if this hook is missing, it's more likely to be present than numbers.Integral
support.
__mro__
lists the inheritance stack of a class:
np.int32.__mro__
Out[30]:
(numpy.int32,
numpy.signedinteger,
numpy.integer,
numpy.number,
numpy.generic,
object)
int.__mro__
Out[31]: (int, object)
For a basic array:
x=np.array([1,2,3])
x.dtype
Out[33]: dtype('int32')
isinstance
of classes on this stack returns True:
isinstance(x[0], np.int32)
Out[37]: True
isinstance(x[0], np.number)
Out[38]: True
int
isn't on this stack:
isinstance(x[0], int)
Out[39]: False
isinstance(x[0], object)
Out[40]: True
item
extracts a value from its numpy
wrapper:
isinstance(x[0].item(), int)
Out[41]: True
@kazemakase suggests using the numbers
module:
isinstance(x[0], numbers.Integral)
Out[47]: True
edit
isinstance
accepts a tuple of classes, so we can handle both the int
and numpy
cases with one test:
In [259]: isinstance(x[0], (int,np.integer))
Out[259]: True
In [260]: isinstance(x[0].item(), (int,np.integer))
Out[260]: True