Каков наилучший способ проверить, принадлежит ли данный объект заданному типу? Как насчет проверки, наследуется ли объект от данного типа?
Допустим, у меня есть объект o
. Как я могу проверить, является ли это str
?
Каков наилучший способ проверить, принадлежит ли данный объект заданному типу? Как насчет проверки, наследуется ли объект от данного типа?
Допустим, у меня есть объект o
. Как я могу проверить, является ли это str
?
Ответы:
Чтобы проверить, o
является ли экземпляр str
или какой-либо подкласс класса str
, используйте isinstance (это будет «канонический» способ):
if isinstance(o, str):
Чтобы проверить, o
точно ли тип str
(исключая подклассы):
if type(o) is str:
Следующее также работает, и может быть полезно в некоторых случаях:
if issubclass(type(o), str):
См. Встроенные функции в Библиотеке Python для получения соответствующей информации.
Еще одно замечание: в этом случае, если вы используете Python 2, вы можете использовать:
if isinstance(o, basestring):
потому что это также будет ловить строки Unicode ( unicode
не является подклассом str
; оба str
и unicode
являются подклассами basestring
). Обратите внимание, что basestring
больше не существует в Python 3, где существует строгое разделение строк ( str
) и двоичных данных ( bytes
).
Кроме того, isinstance
принимает кортеж классов. Это вернет, True
если o
является экземпляром любого подкласса любого из (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
тогда не правда ли это тоже isinstance(a, Object)
. Однако, если type(a) is SubClassOfObject
, тогда type(a) is Object == False
, но isinstance(a, Object) == True
. Правильно?
a is b
означает, что a и b - это одно и то же, то есть ссылки на один и тот же объект в памяти. Так a
и b
должно быть точно такой же класс, а не подклассы, как с isinstance()
. Смотрите, например, stackoverflow.com/a/133024/1072212
Наиболее Pythonic способ проверить тип объекта является ... не проверить.
Поскольку Python поощряет Duck Typing , вы должны просто try...except
использовать методы объекта так, как вы хотите их использовать. Так что если ваша функция ищет доступный для записи объект файла, не проверяйте, является ли он подклассом file
, просто попробуйте использовать его .write()
метод!
Конечно, иногда эти красивые абстракции ломаются и isinstance(obj, cls)
это то, что вам нужно. Но используйте экономно.
if hasattr(ob, "write") and callable(ob.write):
Или сохранить некоторый доступ к func = getattr(ob, "write", None)
if callable(func): ...
hasattr
только ошибка AttributeError - см. docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
вернет, True
если o
является str
или имеет тип, который наследуется от str
.
type(o) is str
вернется, True
если и только если o
это ул. Он вернетсяFalse
если o
имеет тип, который наследуется от str
.
isinstance
и type(var) == type('')
не ясна.
После того, как вопрос был задан и получен ответ, в Python были добавлены подсказки типа . Подсказки типов в Python позволяют проверять типы, но совсем не так, как в статически типизированных языках. Подсказки типов в Python связывают ожидаемые типы аргументов с функциями как доступные во время выполнения данные, связанные с функциями, и это позволяет проверять типы. Пример синтаксиса подсказки типа:
def foo(i: int):
return i
foo(5)
foo('oops')
В этом случае мы хотим, чтобы была вызвана ошибка, foo('oops')
поскольку аннотированный тип аргумента - int
. Добавленная подсказка типа не вызывает возникновению ошибки при нормальной работе скрипта. Однако в функцию добавляются атрибуты, описывающие ожидаемые типы, которые другие программы могут запрашивать и использовать для проверки ошибок типов.
Одной из этих других программ, которые можно использовать для обнаружения ошибки типа, является mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Вам может понадобиться установить mypy
из вашего менеджера пакетов. Я не думаю, что он поставляется с CPython, но, похоже, имеет некоторый уровень "официальности".)
Проверка типов этим способом отличается от проверки типов в статически типизированных компилируемых языках. Поскольку в Python типы являются динамическими, проверка типов должна выполняться во время выполнения, что требует затрат - даже для правильных программ - если мы настаиваем на том, чтобы это происходило при каждом удобном случае. Явные проверки типов также могут быть более строгими, чем необходимо, и приводить к ненужным ошибкам (например, действительно ли аргумент должен быть точноlist
типа или достаточно итеративен?).
Преимущество явной проверки типов в том, что она может отлавливать ошибки раньше и давать более четкие сообщения об ошибках, чем утка. Точные требования к типу утки могут быть выражены только с помощью внешней документации (надеюсь, она тщательна и точна), и ошибки несовместимых типов могут возникать далеко от их происхождения.
Подсказки типов в Python предназначены для компромисса, когда типы можно указывать и проверять, но при обычном выполнении кода никаких дополнительных затрат не возникает.
В typing
переменных пакета предложений типа , которые могут быть использованы в намеков типа выражать необходимые модели поведения , не требуя определенных типов. Например, он включает в себя такие переменные, какIterable
и Callable
для подсказок, чтобы указать необходимость любого типа с этими поведениями.
В то время как подсказки типов - это самый Pythonic способ проверки типов, часто Pythonic вообще не проверяет типы вообще и полагается на типизацию с утиным типом. Типовые подсказки являются относительно новыми, и жюри все еще остается в стороне, когда они являются наиболее питонским решением. Относительно неоспоримое, но очень общее сравнение: подсказки типов предоставляют форму документации, которую можно применять, позволяют генерировать код раньше и легче понимать ошибки, могут отлавливать ошибки, которые не могут быть введены при печати, и могут быть проверены статически (в необычном случае). смысл, но это все еще вне времени выполнения). С другой стороны, типизация утки долгое время была питонской, не накладывает когнитивных издержек на статическую типизацию, менее многословна и будет принимать все жизнеспособные типы, а затем и некоторые.
mypy
представляют собой модуль Python, который использует importlib
для доступа к этим данным. Является ли это «статической проверкой типов» - это философский вопрос, но он отличается от того, чего большинство ожидают, поскольку в нем задействованы обычный интерпретатор языка и механизм импорта.
Вот пример, почему печатание на уток - зло, не зная, когда это опасно. Например: вот код Python (возможно, без правильного отступа), обратите внимание, что этой ситуации можно избежать, если позаботиться о функциях isinstance и issubclassof, чтобы убедиться, что когда вам действительно нужна утка, вы не получите бомбу.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
и переопределить talk (). Или, более вероятно, class ChineseCancerDuck(Duck)
с неприятным побочным эффектом, который проявляется только спустя годы. Тебе было бы лучше просто присматривать за своим ребенком (и тщательно проверять его игрушки :)
__file__
атрибут (обычно используемый для идентификации файловых объектов), чтобы обозначить что-то другое.
isinstance(o, str)
Я думаю, что классная вещь в использовании динамического языка, такого как Python, заключается в том, что вам не нужно проверять что-то подобное.
Я бы просто вызвал необходимые методы для вашего объекта и поймал бы AttributeError
. Позже это позволит вам вызывать ваши методы с другими (казалось бы, не связанными) объектами для выполнения различных задач, таких как насмешка над объектом для тестирования.
Я использовал это много, когда получаю данные из Интернета с urllib2.urlopen()
которых возвращал файл, подобный объекту. Это, в свою очередь, может быть передано практически любому методу, который читает из файла, потому что он реализует то же самоеread()
метод, что и реальный файл.
Но я уверен, что есть время и место для использования isinstance()
, иначе его, вероятно, не было бы :)
Для более сложных проверок типов мне нравится подход валидации typeguard, основанный на аннотациях подсказок типа Python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Вы можете выполнять очень сложные проверки в очень чистой и удобочитаемой форме.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Вы можете проверить тип переменной, используя __name__ типа.
Пример:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Хьюго:
Вы, вероятно, имеете в виду, list
а неarray
, но это указывает на всю проблему с проверкой типов - вы не хотите знать, является ли рассматриваемый объект списком, вы хотите знать, является ли это какой-то последовательностью или это один объект. Поэтому попробуйте использовать его как последовательность.
Допустим, вы хотите добавить объект в существующую последовательность или, если это последовательность объектов, добавить их все
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Одна хитрость в этом заключается в том, что если вы работаете со строками и / или последовательностями строк - это сложно, поскольку строку часто рассматривают как отдельный объект, но это также последовательность символов. Хуже того, так как это действительно последовательность строк одинарной длины.
Я обычно выбираю дизайн своего API так, чтобы он принимал только одно значение или последовательность - это облегчает работу. Нетрудно [ ]
обойти ваше единственное значение, когда вы передаете его, если это необходимо.
(Хотя это может привести к ошибкам со строками, так как они выглядят (являются) последовательностями.)
Простой способ проверить тип - сравнить его с чем-то, чей тип вы знаете.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Я думаю, что лучший способ - это правильно набирать переменные. Вы можете сделать это с помощью библиотеки "typing".
Пример:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Вы можете проверить с помощью строки ниже, чтобы проверить, какой тип символа заданное значение:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)