Как я могу проверить типы переменных в Python?

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

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

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

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

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

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

Дубликат: stackoverflow.com/questions/378927/…

S.Lott 21.01.2009 03:29

Итак, должно ли n быть целым числом или должно быть только целым числом?

user3850 21.01.2009 04:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
34
2
42 699
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий
isinstance(n, int)

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

type(n) is int

это:

return int(n) == n

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

Я обнаружил функцию «тип» примерно через 5 минут после публикации вопроса. :) Ради интереса, есть ли какое-либо существенное снижение производительности при использовании 'isInstance' вместо 'type'?

Murali Suriar 21.01.2009 03:14

Во всяком случае, я ожидал, что isinstance будет быстрее. Однако разница не должна быть большой (и если вы действительно обеспокоенный о производительности, почему вы используете Python?)

David Z 21.01.2009 03:17

@David: Меня не беспокоит производительность именно этой программы; это прототип хобби-проекта, от которого можно или не отказаться. Тем не менее, меня интересует разница между двумя подходами и компромиссы, связанные с каждым из них. Больше скорости никогда не бывает плохо. :)

Murali Suriar 21.01.2009 03:20

timeit.Timer () говорит, что type-is-int примерно на 4% быстрее, чем isinstance-int на моей машине с Python 2.6. В любом случае это довольно незначительно, выбирайте тот, который лучше всего говорит о том, что вы имеете в виду.

bobince 21.01.2009 03:45

-1: проверка типов - не лучшая идея. Вы должны сказать это в своем ответе.

nosklo 21.01.2009 13:43

Конечно, есть случаи, когда уместна проверка типов. Не зная, что делает OP - только то, что это "должен" целое число - пока рано осуждать.

bobince 21.01.2009 16:07

@bobince: проверка типов - это плохо во всех ситуациях. Я не могу представить себе ситуацию, в которой проверка типа принесла бы пользу.

nosklo 21.01.2009 16:56

nosklo: аргументы вариантов, конструкторы вариантов, обработка str / unicode, проверка исключений, getitem ... проверка типов осуществляется повсюду в Python. Отбросьте догму ОО и живите с ней.

bobince 21.01.2009 18:09

@bobince, проверка типов не требуется. Вместо этого поймайте TypeError, чтобы знать, что он несовместим.

Evan Fosmark 21.01.2009 20:36

Эван: Кто сказал, что будет исключение? Он может работать, но вести себя некорректно. Без дополнительного контекста из OP мы не знаем, подходит ли это место для проверки типов.

bobince 21.01.2009 20:49

@bobince: проверка типа подходит для никогда. Это глупо. Доказательство тому, что вы не могли придумать ситуацию, в которой его следовало бы использовать. Ни один из ваших примеров: «аргументы вариантов, конструкторы вариантов, обработка str / unicode, проверка исключений, getitem» каким-либо образом не использует проверку типов.

nosklo 22.01.2009 22:26

Все они используют проверку типов, поэтому я упомянул их. У вас может быть аргумент, если OP определяли свои собственные типы значений, но факт в том, что вы не можете поместить свои собственные инкапсулированные действия внутри int и других встроенных типов. Тем не менее, спасибо, что сказал мне, что это «глупо» - хороший аргумент!

bobince 23.01.2009 04:31

@bobince: они не используют проверку типов! Варианты аргументов никаким образом не используют проверку типов, а только * args, возвращающие кортеж. конструкторы вариантов тоже этого не делают, вы просто создаете для этого дополнительные методы класса. обработка str / unicode также ... просто относитесь ко всему как к unicode. Встроенная проверка исключений.

nosklo 23.01.2009 14:41

@bobince: а getitem? Я даже не понимаю, как это будет использовать проверку типов. А то, что я не могу поместить свои действия во встроенные типы, - это плохая проверка типов очень причина !! Без проверки типов мне вообще не нужно использовать встроенные типы, поэтому я могу использовать свои действия а также, он все еще работает.

nosklo 23.01.2009 14:43
getitem может принимать числовую позицию, произвольный ключ или объект среза в качестве аргумента. Это пример вариантных аргументов (не переменной длины). Как узнать, что вы прошли? С isinstance. dict может быть создан из последовательности или сопоставления с другой семантикой ... и т. д.
bobince 23.01.2009 14:51

... и обнаружение разницы между str и unicode жизненно важно в программе, которая не хочет заканчивать случайными UnicodeDecodeErrors. Я не утверждаю, что проверка типов - это здорово, и, конечно, ее следует избегать, когда вы контролируете интерфейсы, но полностью избегать этого нецелесообразно.

bobince 23.01.2009 14:56

@bobince В getitem я использую try: start, end, step = item.indices (), кроме AttributeError: something (). diff между unicode и str бесполезен, если вы декодируете все, что получаете извне python, и перекодируете весь вывод, поэтому вы заканчиваете только внутренним unicode (это то, что представляет собой py3.0 str)

nosklo 23.01.2009 21:03

@bobince Если я напишу свой собственный класс dict, я предпочитаю использовать альтернативный конструктор для сопоставлений, но я мог бы попробовать: arg = arg.iteritems () except AttributeError: pass then for key, value in arg

nosklo 23.01.2009 21:04

@bobince: Дело в том, что ваше последнее предложение неверно. Я всегда могу полностью избежать проверки типов и быть счастливым. Фактически, я делаю это во всех написанных мною программах.

nosklo 23.01.2009 21:05

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

Gareth Latty 08.01.2013 14:07
if type(n) is int

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

Однако проверка типов не соответствует «пути Python». Лучше использовать n как int, и если он вызывает исключение, поймайте его и действуйте в соответствии с ним.

Давайте, ребята. Ответ на вопрос оказался полезным, хотя и не очень. Вместо того, чтобы голосовать против, исправьте это, потому что, если многие люди согласятся, что проверка типов не очень Pythonic, правильное сообщение может быть легче доставлено.

tzot 21.01.2009 16:58

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

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

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

Nick 21.01.2009 08:03

+1: Лучше не проводить проверку типов. @Nick: вы можете привести пример такой функции? Почему я не могу передать значение с плавающей запятой в функцию, которой требуется целое число? Вместо проверки типов следует использовать int () для значения.

nosklo 21.01.2009 13:48

@nosklo: если у вас есть функция, которая требует в качестве аргумента int, скажем, потому что это длина массива или какое-то другое целое число, тогда использование int () для сжатия может скрыть ошибки. Во многих случаях программы должны преждевременно выходить из строя при получении недопустимого ввода, а не пытаться молча исправить ввод.

Nick 07.04.2009 20:53

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

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

Он сказал, что функция не будет работать, если аргумент не является int. Если функция "работает" с числами с плавающей запятой и комплексными числами, потому что она не проверяется по типу, это ошибка, а не особенность.

Nick 21.01.2009 08:02

@Nick: Если это не сработает, если аргумент не является int, что он будет делать вместо этого? Поднять ошибку? Ну, Python это уже делает. Кроме того, если функция работает с другими типами, такими как float, то это не ошибка, это особенность, потому что функция - это за работой. Сделать так, чтобы это не работало, было бы искусственным ограничением.

nosklo 21.01.2009 13:46

@Nick: Как вы можете знать, что функция не будет работать без int? Что, если я предоставлю объект, который не является int, но ведет себя точно так же, как int? Почему это не должно работать?

nosklo 21.01.2009 15:01

@nosklo: функция может «работать» при передаче другого аргумента, но для целей задачи результат должен быть «неопределенным». Я никогда не слышал о нецелой длине префикса.

Murali Suriar 22.01.2009 13:33

@Murali: Тогда просто используйте int () для значения. Это превратит его в целое число.

nosklo 22.01.2009 22:23

@nosklo: Может, я не понимаю? Если полученное значение не является int, значит, ввод недопустим, и программа не должна с ним ничего делать.

Murali Suriar 23.01.2009 17:36

@ Мурали, да, но почему? Это искусственное ограничение. Доказательство плохо разработанной спецификации.

nosklo 23.01.2009 20:59

@nosklo: общепринятый формат для префиксов CIDR IPv4 - A.B.C.D / E, где A-D - целые числа в диапазоне 0–255, а E - это целое число в диапазоне 0–32. Если вышеуказанные условия не выполняются, входной файл имеет неправильный формат, и его следует игнорировать. Я упускаю здесь что-то очевидное? Что делает этот дизайн плохим?

Murali Suriar 23.01.2009 22:25

@Murali: Часть «следует игнорировать» - плохой дизайн. Кроме того, похоже, что задача библиотеки подчеркивания - правильно обрабатывать эти числа, а не вашей библиотеки. И просто вызов int () для значения означает, что вы можете передавать строки, числа с плавающей запятой ... и при этом соответствовать критериям, поэтому я не понимаю, почему бы и нет.

nosklo 23.01.2009 23:13

@Murali: вызов int () является более быстрым, простым и читаемым кодом, который будет работать во всех случаях, за исключением искусственного ограничения «должно быть целым числом или умереть». И вы теряете возможность использовать другие типы. Так что отказ от проверки типов - беспроигрышный вариант

nosklo 23.01.2009 23:16

@Murali: Лучшим вариантом будет: Общепринятый формат для префиксов IPv4 CIDR - A.B.C.D / E, где A-D - целые числа в диапазоне 0–255, а E - это целое число в диапазоне 0–32. Если вышеуказанные условия не выполняются и значения не могут быть легко преобразованы в целые числа, должна возникнуть ошибка.

nosklo 23.01.2009 23:17

@nosklo: Это другой дизайн; не обязательно лучше. Если значения необходимо преобразовать в целые числа (легко или нет), то входные данные не соответствуют ожидаемому формату; что еще может быть не так с вводом? Я предпочитаю игнорировать это раньше, чем исправлять все возможные ошибки позже.

Murali Suriar 24.01.2009 02:43

@Murali: Хорошо, если хотите. В конце моего ответа добавлен способ сделать это так, что вы можете отключить его, если хотите.

nosklo 24.01.2009 21:05

@kigurai: он решает проблему, потому что он гарантирует, что «недопустимые» данные не будут переданы вышестоящей функции, предварительно преобразовав что-либо в int. Если это не то, чего хочет вызывающий, он все равно должен передать мне int, как задокументировано, так что я стараюсь изо всех сил.

nosklo 26.03.2009 20:59

@kigurai: и я рекомендую "upstreamfunction (int (value))" только в том случае, если восходящая функция имеет побочные эффекты, которые вызовут взрыв компьютера, если не передать int. Это очень необычно. Проверка типов бесполезна почти во всех случаях.

nosklo 26.03.2009 21:02

@nosklo: если у вас есть функция, которая требует в качестве аргумента int, скажем, потому что это длина массива или какое-то другое целое число, тогда использование int () для сжатия может скрыть ошибки. Во многих случаях программы должны преждевременно выходить из строя при получении недопустимого ввода, а не пытаться молча исправить ввод.

Nick 07.04.2009 20:54

Ник, конечно, тогда не используйте int () в этом случае. Просто передайте ценность нетронутой. Тип списка вызовет ошибку автоматически, нет необходимости проверять.

nosklo 07.04.2009 21:16

@nick, дело в том, что там нет места для проверки типов, если не добавить "искусственные ограничения".

nosklo 07.04.2009 21:17

Программирование на 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) ...

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 test.py для файлов Python 3 и mypy --py2 test.py для файлов Python 2.

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

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

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

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

Ciro Santilli新疆棉花TRUMP BAN BAD 29.03.2017 13:53

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

assert(type(X) == int(0))

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

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