Каков канонический способ проверки типа в Python?

StackOverflow https://stackoverflow.com/questions/152580

  •  02-07-2019
  •  | 
  •  

Вопрос

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

Допустим, у меня есть объект 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 не является подклассом str;оба str и unicode являются подклассами basestring).Обратите внимание, что basestring больше не существует в Python 3, где есть строгое разделение строк (str) и двоичные данные (bytes).

Альтернативно, isinstance принимает кортеж классов.Это вернет True, если x является экземпляром любого подкласса любого из (str, unicode):

if isinstance(o, (str, unicode)):

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

А большинство Pythonic способ проверить тип объекта...не для того, чтобы это проверить.

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

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

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

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

После того, как вопрос был задан и получен ответ, в 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 type или достаточно ли чего-нибудь итерируемого?).

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

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

А typing Пакет предлагает переменные типа, которые можно использовать в подсказках типов для выражения необходимого поведения, не требуя определенных типов.Например, он включает в себя такие переменные, как Iterable и Callable для подсказок, указывающих необходимость любого типа с таким поведением.

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

Вот пример того, почему утиный набор текста — это зло, не зная, когда это опасно.Например:Вот код 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()

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

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

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

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

Хьюго:

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

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

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

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

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

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

Для более сложных проверок типов мне нравится типгардподход проверки на основе аннотаций подсказок типа 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) 

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

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

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