Как правильно использовать isinstance() Python, чтобы проверить, является ли переменная числом?

Я нашел старый код Python, который делал что-то вроде:

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

Как и ожидалось, pep8 жалуется на эту рекомендацию использования isinstance().

Теперь проблема в том, что модуль numbers был добавлен в Python 2.6, и мне нужно написать код, который работает с Python 2.5+.

Так что if isinstance(var, Numbers.number) не решение.

Какое решение было бы правильным в этом случае?


person sorin    schedule 26.06.2012    source источник
comment
Если вы хотите использовать numpy, numpy.isfinite должен помочь.   -  person Jon Warneke    schedule 10.08.2016


Ответы (3)


В Python 2 вы можете использовать модуль types:

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

Обратите внимание на использование кортежа для проверки нескольких типов.

Под капотом IntType — это просто псевдоним для int и т. д.:

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

Тип complex требует, чтобы ваш Python был скомпилирован с поддержкой комплексных чисел; если вы хотите защитить это, используйте блок try/except:

>>> 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)
...

или если вы просто используете типы напрямую:

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

В Python 3 types больше не имеет псевдонимов стандартных типов, complex всегда включен, и больше нет разницы long и int, поэтому в Python 3 всегда используйте:

NumberTypes = (int, float, complex)

И последнее, но не менее важное: вы можете использовать numbers.Numbers абстрактный базовый тип (новое в Python 2.6), чтобы также поддерживать пользовательские числовые типы, которые не являются прямыми производными от вышеуказанных типов:

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

Эта проверка также возвращает True для объектов decimal.Decimal() и fractions.Fraction().

Этот модуль предполагает, что тип complex включен; вы получите ошибку импорта, если это не так.

person Martijn Pieters    schedule 26.06.2012
comment
@Def_Os: да, и эта функция появилась начиная с Python 2.2. - person Martijn Pieters; 07.12.2016
comment
Вы действительно должны поставить это в верхней части своего ответа. - person Jürgen A. Erhard; 27.02.2017
comment
@JürgenA.Erhard: поставить что вверху? - person Martijn Pieters; 27.02.2017
comment
@MartijnPieters, как вы думаете, следует ли избегать использования isinstance(), как предлагает эта статья. - person lmiguelvargasf; 09.10.2017
comment
@lmiguelvargasf: это довольно широко, но в целом я согласен. Этот ответ касается варианта использования, в котором isinstance() имеет смысл, и в этот момент вы проверяете интерфейс (это то, что в статье говорится о том, что Python не имеет, но на самом деле это то, что ABC). - person Martijn Pieters; 10.10.2017
comment
Глядя на документ, кажется, что types.IntTypes не существует в Python3, правильно ли это, Мартейн? - person Overdrivr; 29.08.2018
comment
@Overdriver: это правильно. Модуль types больше не содержит псевдонимов для int, float и complex (long больше не существует как имя в Python 3, int в Python 3 имеет тот же тип, что и long в Python 2). - person Martijn Pieters; 29.08.2018
comment
Похоже, что numpy.int32 не захвачен int. - person Matthias Arras; 01.02.2021
comment
@MatthiasArras, это не подкласс типа int Python, нет. isinstance(np.int32(32), numbers.Integral) правда, однако. - person Martijn Pieters; 01.02.2021

Python 2 поддерживает четыре типа чисел int, float, long и complex, а python 3.x поддерживает 3: int, float и complex.

>>> num = 10
>>> if isinstance(num, (int, float, long, complex)): #use tuple if checking against multiple types
      print('yes it is a number')

yes it is a number
>>> isinstance(num, float)   
False
>>> isinstance(num, int)
True
>>> a = complex(1, 2)
>>> isinstance(a, complex)
True
person Ashwini Chaudhary    schedule 26.06.2012

В зависимости от того, что вы используете в утиный ввод, может быть лучшим подходом (это конечно обычно рекомендуется). Проблема с подходом Мартина Питерса заключается в том, что вы всегда будете пропускать некоторые типы чисел из своего списка. С моей точки зрения, ваш код не будет работать с: рациональными числами, целыми числами произвольной точности и любой реализацией комплексных чисел.

Один из вариантов — написать такую ​​функцию:

def is_number(thing):
    try:
        thing + 1
        return True
    except TypeError:
        return False

Этот код должен работать с любой разумной реализацией числа. Конечно, есть и существенный недостаток: он также будет работать с неразумной реализацией большого количества нечисел (например, если оператор плюса перегружен и принимает целое число).

Другая альтернатива (в зависимости от того, зачем вам нужно знать, является ли что-то числом) состоит в том, чтобы просто предположить, что это число, и если это не так, ошибки будут выдаваться любым битом кода, требующим числа.

Я не говорю, что эти подходы всегда лучше (в отличие от некоторых людей...), просто их стоит рассмотреть.

person dshepherd    schedule 03.10.2013
comment
Я знаю, что это действительно старо, но... thing + 1 не вызывает TypeError, если thing является логическим значением. Также, если вещь равна numpy.nan, функция возвращает True, что может не иметь смысла. - person Toby Petty; 08.05.2019
comment
Я думаю, что принятие nans разумно: хотя это сокращение от не числа, это все же число с плавающей запятой, которое является числовым типом. Большинство известных мне строго типизированных языков будут компилироваться с нансами в местах, которые принимают числа. Отстойно, что оператор + определен для логических значений, я этого не знал. - person dshepherd; 08.05.2019
comment
... наверняка thing +1 будет работать и не вызовет никаких исключений, если thing является любым массивом numpy или scipy, что, я сомневаюсь, является желаемым поведением, если кто-то хочет ловушку, если var похож на список... - person lurix66; 05.11.2019