Какой канонический способ проверить тип в Python? - PullRequest
1079 голосов
/ 30 сентября 2008

Как лучше всего проверить, принадлежит ли данный объект заданному типу? Как насчет проверки, наследуется ли объект от данного типа?

Допустим, у меня есть объект o. Как я могу проверить, является ли это str?

Ответы [ 10 ]

1317 голосов
/ 30 сентября 2008

Чтобы проверить, является ли 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, если x является экземпляром любого подкласса любого из (str, unicode):

if isinstance(o, (str, unicode)):
173 голосов
/ 30 сентября 2008

Most Pythonic способ проверить тип объекта ... не проверять его.

Поскольку Python поощряет Duck Typing , вам нужно просто try...except использовать методы объекта так, как вы хотите их использовать. Поэтому, если ваша функция ищет доступный для записи объект файла, не проверяйте, что это подкласс file, просто попробуйте использовать его метод .write()!

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

47 голосов
/ 30 сентября 2008

isinstance(o, str) вернет True, если o является str или имеет тип, который наследуется от str.

type(o) is str вернет True тогда и только тогда, когда o является ул. Он вернет False, если o имеет тип, который наследуется от str.

22 голосов
/ 06 мая 2016

После того, как вопрос был задан и получен ответ, в 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 вообще не проверяет типы вообще и полагается на типизацию утки. Типовые подсказки являются относительно новыми, и жюри все еще остается в стороне, когда они являются наиболее питонским решением. Относительно неоспоримое, но очень общее сравнение: подсказки типов предоставляют форму документации, которую можно применять, позволяют генерировать код раньше и легче понимать ошибки, могут отлавливать ошибки, которые не могут быть введены при печати, и могут быть проверены статически (в необычном смысл, но это все еще вне времени выполнения). С другой стороны, типирование утки долгое время оставалось Pythonic, оно не накладывает когнитивных издержек на статическую типизацию, менее многословно и будет принимать все жизнеспособные типы, а затем и некоторые.

17 голосов
/ 26 января 2013

Вот пример того, почему печатание на утках - зло, не зная, когда это опасно. Например: вот код 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()
12 голосов
/ 30 сентября 2008
6 голосов
/ 30 сентября 2008

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

Я бы просто вызвал необходимые методы для вашего объекта и поймал AttributeError. Позже это позволит вам вызывать ваши методы с другими (казалось бы, не связанными) объектами для выполнения различных задач, таких как насмешка над объектом для тестирования.

Я часто использовал это, когда получал данные из Интернета с помощью urllib2.urlopen(), который возвращает файл, такой как объект. Это, в свою очередь, может быть передано практически любому методу, который читает из файла, поскольку он реализует тот же метод read(), что и реальный файл.

Но я уверен, что есть время и место для использования isinstance(), иначе его, вероятно, не было бы:)

4 голосов
/ 01 августа 2012

Уго:

Вы, вероятно, имеете в виду list, а не array, но это указывает на всю проблему проверки типов - вы не хотите знать, является ли рассматриваемый объект списком, вы хотите знать, является ли он каким-то последовательности или, если это один объект. Поэтому попробуйте использовать его как последовательность.

Допустим, вы хотите добавить объект в существующую последовательность или, если это последовательность объектов, добавить их все

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

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

Я обычно выбираю дизайн своего API так, чтобы он принимал только одно значение или последовательность - это облегчает задачу. Нетрудно поместить [ ] вокруг вашего единственного значения, когда вы передаете его, если это необходимо.

(Хотя это может привести к ошибкам со строками, так как они выглядят (являются) последовательностями.)

1 голос
/ 16 февраля 2019

Для более сложных проверок типов мне нравится 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) 
0 голосов
/ 06 апреля 2017

Вы можете проверить с помощью строки ниже, чтобы проверить, какой тип символа заданное значение:

def chr_type(chrx):
    if chrx.isalpha()==True:
        return 'alpha'
    elif chrx.isdigit()==True:
        return 'numeric'
    else:
        return 'nothing'

chr_type("12)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...