Який найкращий спосіб перевірити, чи є даний об’єкт даного типу? Як щодо перевірки, чи успадковується об’єкт від заданого типу?
Скажімо, у мене є об’єкт o
. Як перевірити, чи є це str
?
Який найкращий спосіб перевірити, чи є даний об’єкт даного типу? Як щодо перевірки, чи успадковується об’єкт від заданого типу?
Скажімо, у мене є об’єкт o
. Як перевірити, чи є це str
?
Відповіді:
Щоб перевірити, чи o
це екземпляр str
чи якийсь підклас str
, використовуйте isin substance (це був би "канонічний" спосіб):
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 , вам слід просто 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
це str. Він повернеться, 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
підказки для уточнення потреби в будь-якому типі з такою поведінкою.
Хоча підказки типу є найбільш піфонічним способом перевірки типів, часто навіть пітонічніше навіть не перевіряти типи і покладатися на друкування качок. Підказки щодо типу є відносно новими, і присяжні все ще залишаються на виборах, коли вони є найбільш пітонічним рішенням. Порівняно неперервне, але дуже загальне порівняння: Підказки типу надають форму документації, яку можна застосувати, дозволяють коду генерувати раніше та простіше зрозуміти помилки, вловлювати помилки, які введення качки не може, і їх можна перевірити статично (у незвичній сенс, але це все ще поза часом виконання). З іншого боку, набирання качок вже давно є піфонічним способом, не нав'язує когнітивних накладів статичного набору тексту, є менш багатослівним і сприймає всі життєздатні типи, а потім і деякі.
mypy
є модулем Python, який використовує importlib
для доступу до цих даних. Чи це "перевірка статичного типу" - це філософське питання, але воно відрізняється від того, що більшість очікує, оскільки в них задіяні звичайний перекладач мови та імпортна техніка.
Ось приклад, чому набирати качок - це зло, не знаючи, коли це небезпечно. Наприклад: Ось код Python (можливо, опускаючи належне відступ), зауважте, що цю ситуацію можна уникнути, піклуючись про функції речовини та 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)
та перекрити розмову (). Або, швидше за все, class ChineseCancerDuck(Duck)
з неприємним побічним ефектом, який проявляється лише через роки. Вам буде краще просто контролювати свою дитину (і ретельно випробовувати її іграшки :)
__file__
атрибут (зазвичай використовується для ідентифікації файлоподібних об'єктів), щоб означати щось інше.
isinstance(o, str)
Я думаю, що цікаво про використання динамічної мови на зразок Python - це вам насправді не потрібно перевіряти щось подібне.
Я б просто зателефонував потрібним методам на ваш об'єкт і впіймав AttributeError
. Згодом це дозволить вам викликати свої методи з іншими (здавалося б, не пов'язаними) об'єктами для виконання різних завдань, таких як знущання над об'єктом для тестування.
Я багато використовував це, коли вилучав дані з Інтернету, з urllib2.urlopen()
якими повертає файл, як об’єкт. Це, в свою чергу, може бути передано майже будь-якому методу, який читається з файлу, оскільки він реалізує той самий read()
метод, що і реальний файл.
Але я впевнений, що є час і місце для використання isinstance()
, інакше його, мабуть, не було б :)
Для більш складних перевірок типів мені подобається підхід перевірки вантажів на основі підказки типу 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
Я думаю, що найкращий спосіб - це добре ввести свої змінні. Це можна зробити за допомогою бібліотеки "набору тексту".
Приклад:
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)