Каков самый питонический способ проверить, является ли объект числом?
учитывая произвольный объект python, каков наилучший способ определить, является ли это число? Здесь is определяется как acts like a number in certain circumstances.
например, скажем, вы пишете класс Vector. Если задан другой вектор, вы хотите найти точечный продукт. Если задан скаляр, вы хотите масштабировать весь вектор.
проверка, если что-то int,float,long,bool раздражает и не охватывает пользовательские объекты, которые могут действовать как числа. Но, проверяя ибо __mul__, например, недостаточно хорош, потому что векторный класс, который я только что описал, определит __mul__, но это будет не тот номер, который я хочу.
11 ответов:
использовать
NumberСnumbersмодуль для тестированияisinstance(n, Number)(доступен начиная с 2.6).>>> from numbers import Number ... from decimal import Decimal ... from fractions import Fraction ... for n in [2, 2.0, Decimal('2.0'), complex(2,0), Fraction(2,1), '2']: ... print '%15s %s' % (n.__repr__(), isinstance(n, Number)) 2 True 2.0 True Decimal('2.0') True (2+0j) True Fraction(2, 1) True '2' FalseЭто, конечно, противоречит утиной типизацией. Если вы больше беспокоитесь о том, как объект действия а не то, что он и, выполняйте свои операции, как будто у вас есть число и используйте исключения, чтобы сказать вам иначе.
вы хотите проверить, если какой-то объект
действует как число в некоторых обстоятельства
если вы используете Python 2.5 или старше, единственный реальный способ-проверить некоторые из этих "определенных обстоятельств" и посмотреть.
в 2.6 или лучше, вы можете использовать
isinstanceС цифры.Номер -- абстрактный базовый класс (ABC), который существует именно для этой цели (вcollectionsмодуль для различных форм коллекции / контейнеры, снова начиная с 2.6; и, также только в этих выпусках, вы можете легко добавить свои собственные абстрактные базовые классы, если вам нужно).Бах до 2,5 и ранее, "можно добавить к
0и не повторяется" может быть хорошим определением в некоторых случаях. Но, вы действительно должны спросить себя, что это такое, что вы спрашиваете, что вы хотите рассмотреть "число", безусловно, должны быть в состоянии do, а какой она должна быть абсолютно можете - и проверить.это также может потребоваться в 2.6 или более поздней версии, возможно, с целью создания собственных регистраций для добавления типов, которые вам небезразличны, которые еще не зарегистрированы на
numbers.Numbers-- если вы хотите исключить некоторые типы, которые утверждают, что они числа, но вы просто не можете справиться, что принимает еще большую осторожность, как Азбука не имеютunregisterметод [[например, вы могли бы сделать свой собственный ABCWeirdNumи зарегистрировать там все такие странные для вас типы, а затем сначала проверить ибоisinstanceиз них, чтобы выручить, прежде чем приступить к проверке наisinstanceнормальногоnumbers.Numberдля успешного продолжения.кстати, если и когда вам нужно проверить, если
xможет или не может что-то сделать, вы обычно должны попробовать что-то вроде:try: 0 + x except TypeError: canadd=False else: canadd=Trueв присутствии
__add__per se не говорит вам ничего полезного, так как, например, все последовательности имеют его с целью конкатенации с другими последовательностями. Эта проверка эквивалентна определению " число равно что-то такое, что последовательность таких вещей является допустимым единственным аргументом для встроенной функцииsum", например. Совершенно странные типы (например, те, которые вызывают "неправильное" исключение при суммировании до 0, например, AZeroDivisionErrorилиValueError&c) будет распространяться исключение, но это нормально, пусть пользователь знает как можно скорее, что такие сумасшедшие типы просто не приемлемы в хорошей компании; -); но, "вектор", который суммируется со скаляром (стандартная библиотека Python не имеет его, но, конечно, они популярны как сторонние расширения) также даст неправильный результат здесь, так что (например) эта проверка должна прийти после "не допускается повторяемость" (например, проверьте, чтоiter(x)поднимаетTypeError, или для наличия специального метода__iter__-- если вы находитесь в 2.5 или ранее, и поэтому вам нужны ваши собственные проверки).краткого взгляда на такие осложнения может быть достаточно, чтобы мотивировать вас полагаться вместо этого на абстрактные базовые классы, когда это возможно...;-).
Это хороший пример, когда исключения действительно сиять. Просто сделайте то, что вы хотели бы сделать с числовыми типами и поймать
TypeErrorот всего остального.но очевидно, что это только проверяет, является ли операция работает не будет ли это смысл! Единственное реальное решение для этого-никогда не смешивать типы и всегда точно знать, к какому типу принадлежат ваши значения.
умножьте объект на ноль. Любое число, умноженное на ноль, равно нулю. Любой другой результат означает, что объект не является числом (включая исключения)
def isNumber(x): try: return 0 == x*0 except: return Falseиспользование isNumber таким образом даст следующий результат:
class A: pass def foo(): return 1 for x in [1,1.4, A(), range(10), foo, foo()]: answer = isNumber(x) print '{answer} == isNumber({x})'.format(**locals())выход:
True == isNumber(1) True == isNumber(1.4) False == isNumber(<__main__.A instance at 0x7ff52c15d878>) False == isNumber([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) False == isNumber(<function foo at 0x7ff52c121488>) True == isNumber(1)вероятно, в мире есть некоторые объекты без числа, которые определяют
__mul__чтобы вернуть ноль при умножении на ноль, но это крайнее исключение. Это решение должно охватывать все нормальный и вменяемого код, который вы создаете / encouter.
перефразировать ваш вопрос, вы пытаетесь определить, является ли что-то в коллекцию или единичное значение. Попытка сравнить, является ли что - то вектором или числом, сравнивает яблоки с апельсинами-у меня может быть вектор строк или чисел, и у меня может быть одна строка или одно число. вы заинтересованы в том, сколько у вас есть (1 или более), не то, что тип у вас на самом деле есть.
мое решение этой проблемы-проверить, является ли вход единственным значением или коллекция, проверяя наличие
__len__. Например:def do_mult(foo, a_vector): if hasattr(foo, '__len__'): return sum([a*b for a,b in zip(foo, a_vector)]) else: return [foo*b for b in a_vector]или, для подхода к набору утки, вы можете попробовать повторить
fooпервый:def do_mult(foo, a_vector): try: return sum([a*b for a,b in zip(foo, a_vector)]) except TypeError: return [foo*b for b in a_vector]в конечном счете, легче проверить, является ли что-то векторным, чем проверить, является ли что-то скалярным. Если у вас есть значения разного типа (например, строковые, числовые и т. д.) проходя, то логика вашей программы может потребоваться некоторая работа - как вы в конечном итоге пытаетесь умножить строку на a числовой вектор в первую очередь?
вероятно, лучше просто сделать это наоборот: вы проверяете, является ли это вектором. Если это так, вы делаете точечный продукт, а во всех других случаях вы пытаетесь скалярное умножение.
проверка вектора легко, так как он должен вашего типа векторного класса (или наследуется от него). Вы также можете просто попробовать сначала сделать точечный продукт, и если это не удастся (= это был не совсем вектор), а затем вернуться к скалярному умножению.
просто добавить. Возможно, мы можем использовать комбинацию isinstance и isdigit следующим образом, чтобы найти, является ли значение числом (int, float и т. д.)
Если isinstance(num1, int) или isinstance (num1 , float) или num1.isdigit():
чтобы обобщить / оценить существующие методы:
Candidate | type | delnan | mat | shrewmouse | ant6n ------------------------------------------------------------------------- 0 | <type 'int'> | 1 | 1 | 1 | 1 0.0 | <type 'float'> | 1 | 1 | 1 | 1 0j | <type 'complex'> | 1 | 1 | 1 | 0 Decimal('0') | <class 'decimal.Decimal'> | 1 | 0 | 1 | 1 True | <type 'bool'> | 1 | 1 | 1 | 1 False | <type 'bool'> | 1 | 1 | 1 | 1 '' | <type 'str'> | 0 | 0 | 0 | 0 None | <type 'NoneType'> | 0 | 0 | 0 | 0 '0' | <type 'str'> | 0 | 0 | 0 | 1 '1' | <type 'str'> | 0 | 0 | 0 | 1 [] | <type 'list'> | 0 | 0 | 0 | 0 [1] | <type 'list'> | 0 | 0 | 0 | 0 [1, 2] | <type 'list'> | 0 | 0 | 0 | 0 (1,) | <type 'tuple'> | 0 | 0 | 0 | 0 (1, 2) | <type 'tuple'> | 0 | 0 | 0 | 0(Я пришел сюда этот вопрос)
код
#!/usr/bin/env python """Check if a variable is a number.""" import decimal def delnan_is_number(candidate): import numbers return isinstance(candidate, numbers.Number) def mat_is_number(candidate): return isinstance(candidate, (int, long, float, complex)) def shrewmouse_is_number(candidate): try: return 0 == candidate * 0 except: return False def ant6n_is_number(candidate): try: float(candidate) return True except: return False # Test candidates = (0, 0.0, 0j, decimal.Decimal(0), True, False, '', None, '0', '1', [], [1], [1, 2], (1, ), (1, 2)) methods = [delnan_is_number, mat_is_number, shrewmouse_is_number, ant6n_is_number] print("Candidate | type | delnan | mat | shrewmouse | ant6n") print("-------------------------------------------------------------------------") for candidate in candidates: results = [m(candidate) for m in methods] print("{:<12} | {:<25} | {:>6} | {:>3} | {:>10} | {:>5}" .format(repr(candidate), type(candidate), *results))
для гипотетического векторного класса:
предположим
v- это вектор, и мы умножаем наx. Если имеет смысл умножить каждый компонентvbyx, мы, вероятно, имели в виду, что, так что попробуйте сначала. Если нет, может быть, мы можем поставить точку? В противном случае это ошибка типа.EDIT -- приведенный ниже код не работает, потому что
2*[0]==[0,0]вместо того, чтобы создаватьTypeError. Я оставляю его, потому что он был прокомментирован.def __mul__( self, x ): try: return [ comp * x for comp in self ] except TypeError: return [ x * y for x, y in itertools.zip_longest( self, x, fillvalue = 0 )
У меня была аналогичная проблема, при реализации своего рода вектор класса. Один из способов проверить число - просто преобразовать его в единицу, т. е. с помощью
float(x)Это должно отклонять случаи, когда x не может быть преобразован в число; но также может отклонять другие типы числоподобных структур, которые могут быть допустимыми, например комплексные числа.
вы можете использовать функцию isdigit ().
>>> x = "01234" >>> a.isdigit() True >>> y = "1234abcd" >>> y.isdigit() False
Comments