mardi 13 mai 2014

python - numeric cohérente de type check - Stack Overflow


Let's leave the ducks in the pond.


Just to make it clear, I'm working with Python 2.7.3.


I was playing with number checks and came across a few things that I found odd:


In [1]: numbers.Number.mro()
Out[1]: [numbers.Number, object]

In [2]: numbers.Complex.mro()
Out[2]: [numbers.Complex, numbers.Number, object]

In [3]: numbers.Real.mro()
Out[3]: [numbers.Real, numbers.Complex, numbers.Number, object]

In [4]: numbers.Rational.mro()
Out[4]: [numbers.Rational, numbers.Real, numbers.Complex,
numbers.Number, object]

In [5]: numbers.Integral.mro()
Out[5]: [numbers.Integral, numbers.Rational, numbers.Real,
numbers.Complex, numbers.Number, object]

This strikes me as... counter-productive and is somewhat contradictory within Python itself (int, float, complex just inherit from object directly):


In [6]: isinstance(int(), complex)
Out[6]: False

In [7]: isinstance(int(), numbers.Complex)
Out[7]: True

Then I wrote the following function:


def numeric_check(num):
print "Is an int:", isinstance(num, int)
print "Is a float:", isinstance(num, float)
print "Is a complex:", isinstance(num, complex)
print "Is a numbers.Number:", isinstance(num, numbers.Number)
print "Is an numbers.Integer:", isinstance(num, numbers.Integral)
print "Is a numbers.Real:", isinstance(num, numbers.Real)
print "Is a numbers.Complex:", isinstance(num, numbers.Complex)
print "Is a numpy.integer:", isinstance(num, numpy.integer)
print "Is a numpy.floating:", isinstance(num, numpy.floating)
print "Is a numpy.complex:", isinstance(num, numpy.complex)

And ran the following loop:


for dtype in [int, float, complex,
numpy.int16, numpy.int32, numpy.int64,
numpy.uint16, numpy.uint32, numpy.uint64,
numpy.float16, numpy.float32, numpy.float64, numpy.complex64]:
num = dtype()
print dtype
numeric_check(num)

I'll spare you the full output but a few excerpts:



type 'int'
Is an int: True
Is a float: False
Is a complex: False
Is a numbers.Number: True
Is an numbers.Integer: True
Is a numbers.Real: True
Is a numbers.Complex: True
Is a numpy.integer: False
Is a numpy.floating: False
Is a numpy.complex: False

So as can be expected from the above, int is an instance of any type in the numbers module. On my machine the default numpy integer is 64bit, let's take a look:



type 'numpy.int64'
Is an int: True
Is a float: False
Is a complex: False
Is a numbers.Number: True
Is an numbers.Integer: True
Is a numbers.Real: True
Is a numbers.Complex: True
Is a numpy.integer: True
Is a numpy.floating: False
Is a numpy.complex: False

It matches the same types as int and additionally passes as a numpy.integer. Let's check a numpy.int16:



type 'numpy.int16'
Is an int: False
Is a float: False
Is a complex: False
Is a numbers.Number: False
Is an numbers.Integer: False
Is a numbers.Real: False
Is a numbers.Complex: False
Is a numpy.integer: True
Is a numpy.floating: False
Is a numpy.complex: False

Ouch, it only passes as a numpy.integer. So my questions:



  1. Is this Sparta?

  2. Is the type separation of the numpy part a design choice?

  3. Duck typing aside, if I wanted to check numeric types am I best off ignoring the numbers module and instead doing the following?


Type checks:


isinstance(num, (int, numpy.integer)
isinstance(num, (float, numpy.floating)
isinstance(num, (complex, numpy.complex)



the classes in numbers are Abstract Base Classes, you can register numpy.int* as Integral:


import numpy as np
import numbers
numbers.Integral.register(numpy.integer)
a = np.int16(100)
isinstance(a, numbers.Integral)

But the range of numpy.int16 is smaller than int, if you do calculation with numpy.int16, overflow may occurred.



Let's leave the ducks in the pond.


Just to make it clear, I'm working with Python 2.7.3.


I was playing with number checks and came across a few things that I found odd:


In [1]: numbers.Number.mro()
Out[1]: [numbers.Number, object]

In [2]: numbers.Complex.mro()
Out[2]: [numbers.Complex, numbers.Number, object]

In [3]: numbers.Real.mro()
Out[3]: [numbers.Real, numbers.Complex, numbers.Number, object]

In [4]: numbers.Rational.mro()
Out[4]: [numbers.Rational, numbers.Real, numbers.Complex,
numbers.Number, object]

In [5]: numbers.Integral.mro()
Out[5]: [numbers.Integral, numbers.Rational, numbers.Real,
numbers.Complex, numbers.Number, object]

This strikes me as... counter-productive and is somewhat contradictory within Python itself (int, float, complex just inherit from object directly):


In [6]: isinstance(int(), complex)
Out[6]: False

In [7]: isinstance(int(), numbers.Complex)
Out[7]: True

Then I wrote the following function:


def numeric_check(num):
print "Is an int:", isinstance(num, int)
print "Is a float:", isinstance(num, float)
print "Is a complex:", isinstance(num, complex)
print "Is a numbers.Number:", isinstance(num, numbers.Number)
print "Is an numbers.Integer:", isinstance(num, numbers.Integral)
print "Is a numbers.Real:", isinstance(num, numbers.Real)
print "Is a numbers.Complex:", isinstance(num, numbers.Complex)
print "Is a numpy.integer:", isinstance(num, numpy.integer)
print "Is a numpy.floating:", isinstance(num, numpy.floating)
print "Is a numpy.complex:", isinstance(num, numpy.complex)

And ran the following loop:


for dtype in [int, float, complex,
numpy.int16, numpy.int32, numpy.int64,
numpy.uint16, numpy.uint32, numpy.uint64,
numpy.float16, numpy.float32, numpy.float64, numpy.complex64]:
num = dtype()
print dtype
numeric_check(num)

I'll spare you the full output but a few excerpts:



type 'int'
Is an int: True
Is a float: False
Is a complex: False
Is a numbers.Number: True
Is an numbers.Integer: True
Is a numbers.Real: True
Is a numbers.Complex: True
Is a numpy.integer: False
Is a numpy.floating: False
Is a numpy.complex: False

So as can be expected from the above, int is an instance of any type in the numbers module. On my machine the default numpy integer is 64bit, let's take a look:



type 'numpy.int64'
Is an int: True
Is a float: False
Is a complex: False
Is a numbers.Number: True
Is an numbers.Integer: True
Is a numbers.Real: True
Is a numbers.Complex: True
Is a numpy.integer: True
Is a numpy.floating: False
Is a numpy.complex: False

It matches the same types as int and additionally passes as a numpy.integer. Let's check a numpy.int16:



type 'numpy.int16'
Is an int: False
Is a float: False
Is a complex: False
Is a numbers.Number: False
Is an numbers.Integer: False
Is a numbers.Real: False
Is a numbers.Complex: False
Is a numpy.integer: True
Is a numpy.floating: False
Is a numpy.complex: False

Ouch, it only passes as a numpy.integer. So my questions:



  1. Is this Sparta?

  2. Is the type separation of the numpy part a design choice?

  3. Duck typing aside, if I wanted to check numeric types am I best off ignoring the numbers module and instead doing the following?


Type checks:


isinstance(num, (int, numpy.integer)
isinstance(num, (float, numpy.floating)
isinstance(num, (complex, numpy.complex)


the classes in numbers are Abstract Base Classes, you can register numpy.int* as Integral:


import numpy as np
import numbers
numbers.Integral.register(numpy.integer)
a = np.int16(100)
isinstance(a, numbers.Integral)

But the range of numpy.int16 is smaller than int, if you do calculation with numpy.int16, overflow may occurred.


0 commentaires:

Enregistrer un commentaire