Какой самый питонический способ проверить, что входные данные являются правильно сформированными числами

У меня есть функция, которая ожидает действительные числа (целые числа или числа с плавающей запятой) в качестве входных данных, и я пытаюсь проверить этот ввод, прежде чем выполнять над ним математические операции.

Мой первый порыв — приводить входные данные как числа с плавающей запятой из блока try-except.

try:
   myinput = float(input)
except:
   raise ValueError("input is not a well-formed number")

Я также мог бы позвонить isinstance(mydata, (float, int, long) ), но список «все это могут быть числа» кажется мне немного неэлегантным.

Какой самый пифонический способ сделать это? Есть ли еще один вариант, который я упустил?


person Kena    schedule 16.12.2008    source источник
comment
Дубликат: stackoverflow.com/questions /354038/   -  person S.Lott    schedule 16.12.2008
comment
Спасибо! Не знаю, как я мог это пропустить.   -  person Kena    schedule 16.12.2008
comment
Хотя в моем случае входные данные не являются строками, они уже являются числами с плавающей запятой или целыми числами.   -  person Kena    schedule 16.12.2008
comment
@Kena: нет разницы между числами, закодированными как строки, и числами неправильного типа. Это все одно. И вопрос тупой. ;-)   -  person S.Lott    schedule 16.12.2008
comment
Python, к сожалению, не согласен, isinstance(1.0, (float)) ложно   -  person Kena    schedule 16.12.2008
comment
(Что может склонить чашу весов в пользу вызова float вместо isinstance, я думаю)   -  person Kena    schedule 16.12.2008
comment
Но я бы не задавал себе этот вопрос, если бы мои входные данные были строками.   -  person Kena    schedule 16.12.2008
comment
Ваша попытка: ... за исключением того, что я нахожу это очень Pythonic.   -  person bortzmeyer    schedule 16.12.2008
comment
@Kena: isinstance(1.0, (float)) не имеет отношения к тому, что я сказал. Я сказал, что float(1.0), float(1), float(1+0j) и float(1L) для Python — это одно и то же.   -  person S.Lott    schedule 16.12.2008
comment
Но как вопрос, который вы связали, может ответить на мой вопрос, который в основном заключается в том, что мне лучше вызывать float или isinstance, когда isinstance в этом случае не сработал бы, поскольку OP работал со строками?   -  person Kena    schedule 16.12.2008
comment
(Вы по-прежнему можете ответить на мой вопрос, используя float(), и тогда ваша функция сможет обрабатывать строки так же, как и числа)   -  person Kena    schedule 16.12.2008


Ответы (4)


Чтобы процитировать себя из Сколько проверка ввода, которую я должен выполнять в своих функциях/методах Python?:

Для вычислений, таких как сумма, факториал и т. д., встроенные проверки типов Python подойдут. Вычисления заканчиваются вызовом add, mul и т. д. для типов, и если они сломаются, они все равно выдадут правильное исключение. Внедряя свои собственные проверки, вы можете сделать недействительными в противном случае работающие входные данные.

Таким образом, лучший вариант — оставить проверку типов Python. Если вычисление завершится ошибкой, проверка типов Python выдаст исключение, поэтому, если вы делаете это самостоятельно, вы просто дублируете код, что означает дополнительную работу от вашего имени.

person Egil    schedule 16.12.2008
comment
Я согласен с этим. Дело в том, что языки сценариев не имеют строго типизированного кода. Я бы добавил, что оператор assert следует использовать больше для отладки. - person Mapad; 16.12.2008
comment
Я согласен; если вы все равно собираетесь генерировать исключение, то почему бы просто не сказать x ** y или что-то еще, зная, что вы получите исключение, если они не являются числами? - person Eli Courtwright; 16.12.2008
comment
Но тогда тип моего исключения более или менее зависит от того, что я делаю, верно? Например, abs(input) вызовет TypeError, а float(input) вызовет ValueError. Должен ли я беспокоиться об этом? - person Kena; 16.12.2008
comment
Нет. Если заморачиваться и все время выкидывать ValueError, то дифференциация по python даст больше информации об ошибке. - person Egil; 16.12.2008

В Python 2.6 и 3.0 была добавлена ​​иерархия числовых абстрактных типов данных, чтобы вы могли выполнить проверку как:

>>> import numbers
>>> isValid = isinstance(myinput , numbers.Real)

numbers.Real будет соответствовать целочисленному типу или типу с плавающей запятой, но не нечисловым типам или комплексным числам (для этого используйте numbers.Complex). Он также будет соответствовать рациональным числам, но, вероятно, вы захотите включить и их. то есть:

>>> [isinstance(x, numbers.Real) for x in [4, 4.5, "some string", 3+2j]]
[True, True, False, False]

К сожалению, все это в Python >= 2.6, поэтому не будет полезно, если вы разрабатываете для 2.5 или более ранней версии.

person Brian    schedule 16.12.2008

Возможно, вы можете использовать комбинацию операторов assert и isinstance. Что-то вроде следующего, я думаю, более питонический способ, поскольку вы выдаете исключение всякий раз, когда ваши входные данные не соответствуют вашим требованиям. К сожалению, я не вижу лучшего определения того, что является допустимым числом, чем ваше. Может быть, кто-то придет с лучшей идеей.

number = (float, int, long)
assert isinstance(mydata, (float, int, long))
person Mapad    schedule 16.12.2008

Я не понимаю вопроса.

Есть две вещи с совершенно разной семантикой, представленные как «альтернативы».

Преобразование типа — это одно. Он работает с любым объектом, который поддерживает __float__, а это могут быть самые разные объекты, лишь немногие из которых являются числовыми.

try:
   myinput = float(input)
except:
   raise ValueError("input is not a well-formed number")
# at this point, input may not be numeric at all
# it may, however, have produced a numeric value

Типовой тест - это другое. Это работает только с объектами, которые являются надлежащими экземплярами определенного набора классов.

isinstance(input, (float, int, long) )
# at this point, input is one of a known list of numeric types

Вот пример класса, который отвечает на float, но все еще не является числовым.

class MyStrangeThing( object ):
    def __init__( self, aString ):
        # Some fancy parsing 
    def __float__( self ):
        # extract some numeric value from my thing

Вопрос «действительные числа (целые или с плавающей запятой)» вообще неактуален. Многие вещи являются «числовыми» и могут использоваться в числовых операциях, но не являются целыми числами или числами с плавающей запятой. Например, вы могли загрузить или создать пакет рациональных чисел.

Нет смысла перепроверять входные данные, если только у вас нет алгоритма, который не будет работать с некоторыми типами. Это редкость, но для некоторых вычислений требуются целые числа, в частности, чтобы они могли выполнять целочисленное деление и операции с остатком. Для них вы можете захотеть утверждать, что ваши значения являются целыми.

person S.Lott    schedule 16.12.2008