Вопрос

У меня есть функция Python, которая принимает числовой аргумент, который должен быть целым числом, чтобы оно вело себя правильно.Каков предпочтительный способ проверки этого в Python?

Моя первая реакция — сделать что-то вроде этого:

def isInteger(n):
    return int(n) == n

Но я не могу отделаться от мысли, что это 1) дорого 2) некрасиво и 3) подвластно милости машинного эпсилона.

Предоставляет ли Python какие-либо собственные средства проверки типов переменных?Или это считается нарушением динамической типизации языка?

РЕДАКТИРОВАТЬ:поскольку многие спрашивали - рассматриваемое приложение работает с префиксами IPv4, получая данные из плоских текстовых файлов.Если какие-либо входные данные преобразуются в число с плавающей запятой, эту запись следует рассматривать как искаженную и игнорировать.

Это было полезно?

Решение

isinstance(n, int)

Если вам нужно знать, действительно ли это фактическое int, а не подкласс int (обычно вам не нужно этого делать):

type(n) is int

return int(n) == n

не очень хорошая идея, так как сравнение между типами может быть правдой - особенно int(3.0)==3.0

Другие советы

Да, как сказал Эван, не печатай чек.Просто попробуйте использовать значение:

def myintfunction(value):
   """ Please pass an integer """
   return 2 + value

Здесь нет проверки типа.Это намного лучше!Посмотрим, что произойдет, когда я попробую:

>>> myintfunction(5)
7

Это работает, потому что это целое число.Хм.Давайте попробуем текст.

>>> myintfunction('text')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myintfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Он показывает ошибку TypeError, что и должно быть в любом случае.Если вызывающий абонент хочет это перехватить, это возможно.

Что бы вы сделали, если бы провели проверку типа?Покажи ошибку, да?Таким образом, вам не нужно проверять тип, потому что ошибка уже появляется автоматически.

Плюс, поскольку вы не проверяли тип, ваша функция работает с другими типами:

Плавает:

>>> print myintfunction(2.2)
4.2

Комплексные числа:

>>> print myintfunction(5j)
(2+5j)

Десятичные дроби:

>>> import decimal
>>> myintfunction(decimal.Decimal('15'))
Decimal("17")

Даже совершенно произвольные предметы, способные складывать числа!

>>> class MyAdderClass(object):
...     def __radd__(self, value):
...             print 'got some value: ', value
...             return 25
... 
>>> m = MyAdderClass()
>>> print myintfunction(m)
got some value:  2
25

Таким образом, вы явно ничего не получите от проверки типов.И потерять многое.


ОБНОВЛЯТЬ:

Поскольку вы отредактировали вопрос, теперь ясно, что ваше приложение вызывает некую вышестоящую процедуру, которая имеет смысл только с целыми числами.

В этом случае я все же думаю, что вам следует передать параметр по получении к восходящей функции.Восходящая функция справится с этим правильно, например.вызов ошибки, если это необходимо.Я очень сомневаюсь в этом ваша функция, работающая с IP-адресами, будет вести себя странно, если вы передадите ей число с плавающей запятой.Если вы дадите нам название библиотеки, мы проверим это для вас.

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

def myintfunction(value):
   """ Please pass an integer """
   return upstreamfunction(int(value))

Вы по-прежнему не выполняете проверку типов, поэтому не выполняете проверку типов и получаете большую часть преимуществ.


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

assert isinstance(...)
assert type() is xxxx

Таким образом, мы можем отключить assertи удали это <sarcasm>особенность</sarcasm> из программы, вызвав ее как

python -OO program.py
if type(n) is int

Это проверяет, является ли n int типа Python и только int. Он не будет принимать подклассы int.

Проверка типов, однако, не подходит для " Python way " ;. Вам лучше использовать <=> как int, и если оно выдает исключение, поймайте его и действуйте в соответствии с ним.

Python теперь поддерживает постепенную печать с помощью модуль ввода и mypy . Модуль typing является частью stdlib начиная с Python 3.5 и может быть загружен из PyPi если вам нужны обратные порты для Python 2 или предыдущей версии Python 3. Вы можете установить mypy, запустив pip install mypy из командной строки.

Короче говоря, если вы хотите проверить, что какая-то функция принимает int, float и возвращает строку, вы должны аннотировать свою функцию следующим образом:

def foo(param1: int, param2: float) -> str:
    return "testing {0} {1}".format(param1, param2)

Если ваш файл был назван test.py, вы можете проверить его после установки mypy, запустив mypy test.py из командной строки.

Если вы используете более старую версию Python без поддержки аннотаций функций, вы можете использовать комментарии типа для достижения того же эффекта:

def foo(param1, param2):
    # type: (int, float) -> str
    return "testing {0} {1}".format(param1, param2)

Вы используете ту же команду mypy --py2 test.py для файлов Python 3, и isinstance для файлов Python 2.

Примечания к типу полностью игнорируются интерпретатором Python во время выполнения, поэтому они накладывают минимальные затраты или не требуют дополнительных затрат - обычный рабочий процесс состоит в том, чтобы работать с вашим кодом и периодически запускать mypy для выявления ошибок и ошибок. Некоторые IDE, такие как PyCharm, понимают подсказки типов и могут предупреждать вас о проблемах и несоответствиях типов в коде во время непосредственного редактирования.

Если по какой-то причине вам необходимо проверить типы во время выполнения (возможно, вам нужно проверить много входных данных?), вы должны следовать советам, перечисленным в других ответах - например, используйте issubclass, <=> и т.п. Существуют также некоторые библиотеки, такие как принудительное применение , которые пытаются выполнять проверку типов (с учетом ваших аннотаций типов) во время выполнения, хотя я не уверен, насколько они готовы к производству на момент написания.

Для получения дополнительной информации и подробностей см. веб-сайт mypy , FAQ по mypy и PEP 484 .

Не проверяйте тип. Все дело в том, что вы не должны этого делать. Например, что если кто-то сделал что-то вроде этого:

class MyInt(int):
    # ... extra stuff ...

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

Из интерактивной командной строки вы можете выполнить инструкцию вроде:

int('sometext')

Это вызовет ошибку - ipython сообщает мне:

<type 'exceptions.ValueError'>: invalid literal for int() with base 10: 'sometext'

Теперь вы можете написать код наподобие:

try:
   int(myvar) + 50
except ValueError:
   print "Not a number"

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

Я бы хотел соблазнить что-то вроде:

def check_and_convert(x):
    x = int(x)
    assert 0 <= x <= 255, "must be between 0 and 255 (inclusive)"
    return x

class IPv4(object):
    """IPv4 CIDR prefixes is A.B.C.D/E where A-D are 
       integers in the range 0-255, and E is an int 
       in the range 0-32."""

    def __init__(self, a, b, c, d, e=0):
        self.a = check_and_convert(a)
        self.b = check_and_convert(a)
        self.c = check_and_convert(a)
        self.d = check_and_convert(a)
        assert 0 <= x <= 32, "must be between 0 and 32 (inclusive)"
        self.e = int(e)

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

как насчет

def ip(string):
    subs = string.split('.')
    if len(subs) != 4:
        raise ValueError("incorrect input")
    out = tuple(int(v) for v in subs if 0 <= int(v) <= 255)
    if len(out) != 4:
        raise ValueError("incorrect input")
    return out

Конечно, есть стандартная функция isinstance (3, int) ...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top