pythonpython-2.5pep8

How to properly use python's isinstance() to check if a variable is a number?


I found some old Python code that was doing something like:

if type(var) is type(1):
   ...

As expected, pep8 complains about this recommending usage of isinstance().

Now, the problem is that the numbers module was added in Python 2.6 and I need to write code that works with Python 2.5+

So if isinstance(var, Numbers.number) is not a solution.

Which would be the proper solution in this case?


Solution

  • In Python 2, you can use the types module:

    >>> import types
    >>> var = 1
    >>> NumberTypes = (types.IntType, types.LongType, types.FloatType, types.ComplexType)
    >>> isinstance(var, NumberTypes)
    True
    

    Note the use of a tuple to test against multiple types.

    Under the hood, IntType is just an alias for int, etc.:

    >>> isinstance(var, (int, long, float, complex))
    True
    

    The complex type requires that your python was compiled with support for complex numbers; if you want to guard for this use a try/except block:

    >>> try:
    ...     NumberTypes = (types.IntType, types.LongType, types.FloatType, types.ComplexType)
    ... except AttributeError:
    ...     # No support for complex numbers compiled
    ...     NumberTypes = (types.IntType, types.LongType, types.FloatType)
    ...
    

    or if you just use the types directly:

    >>> try:
    ...     NumberTypes = (int, long, float, complex)
    ... except NameError:
    ...     # No support for complex numbers compiled
    ...     NumberTypes = (int, long, float)
    ...
    

    In Python 3 types no longer has any standard type aliases, complex is always enabled and there is no longer a long vs int difference, so in Python 3 always use:

    NumberTypes = (int, float, complex)
    

    Last but not least, you can use the numbers.Numbers abstract base type (new in Python 2.6) to also support custom numeric types that don't derive directly from the above types:

    >>> import numbers
    >>> isinstance(var, numbers.Number)
    True
    

    This check also returns True for decimal.Decimal() and fractions.Fraction() objects.

    This module does make the assumption that the complex type is enabled; you'll get an import error if it is not.