Відмінності між Python isinstance()
і type()
в них?
Перевірка типу с
isinstance(obj, Base)
дозволяє застосовувати екземпляри підкласів та декілька можливих баз:
isinstance(obj, (Base1, Base2))
тоді як перевірка типу за допомогою
type(obj) is Base
підтримує лише тип, на який посилається.
Що стосується сиденота, is
швидше за все, більше, ніж
type(obj) == Base
тому що класи - одиночні.
Уникайте перевірки типу - використовуйте поліморфізм (тип качки)
У Python, як правило, ви хочете дозволити будь-який тип для своїх аргументів, ставитесь до нього так, як очікувалося, і якщо об’єкт веде себе не так, як очікувалося, він створить відповідну помилку. Це відоме як поліморфізм, також відомий як типинг качок.
def function_of_duck(duck):
duck.quack()
duck.swim()
Якщо наведений вище код працює, ми можемо припустити, що наш аргумент - качка. Таким чином, ми можемо передати інші фактичні підтипи качки:
function_of_duck(mallard)
або які працюють як качка:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
і наш код все ще працює.
Однак є деякі випадки, коли бажано чітко перевірити тип. Можливо, у вас є розумні речі, що стосуються різних типів об'єктів. Наприклад, об'єкт фрейму даних Pandas може бути побудований з диктів або записів. У такому випадку ваш код повинен знати, який тип аргументу він отримує, щоб він міг правильно обробити його.
Отже, щоб відповісти на запитання:
Відмінності між Python isinstance()
і type()
в них?
Дозвольте мені продемонструвати різницю:
type
Скажіть, що вам потрібно забезпечити певну поведінку, якщо ваша функція отримує певний тип аргументу (звичайний випадок використання для конструкторів). Якщо ви перевірите такий тип:
def foo(data):
'''accepts a dict to construct something, string support in future'''
if type(data) is not dict:
# we're only going to test for dicts for now
raise ValueError('only dicts are supported for now')
Якщо ми спробуємо передати дік, який є підкласом dict
(як ми могли б, якщо ми очікуємо, що наш код буде дотримуватися принципу заміни Ліскова , то підтипи можуть бути замінені на типи) наш код порушується !:
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
викликає помилку!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a dict
isinstance
Але якщо ми використаємо isinstance
, ми можемо підтримати Лісков Заміну !:
def foo(a_dict):
if not isinstance(a_dict, dict):
raise ValueError('argument must be a dict')
return a_dict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
повертає OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Анотація базових класів
Насправді ми можемо зробити ще краще. collections
надає абстрактні базові класи, які застосовують мінімальні протоколи для різних типів. У нашому випадку, якщо ми очікуємо лише Mapping
протоколу, ми можемо зробити наступне, і наш код стає ще більш гнучким:
from collections import Mapping
def foo(a_dict):
if not isinstance(a_dict, Mapping):
raise ValueError('argument must be a dict')
return a_dict
Відповідь на коментар:
Слід зазначити, що тип можна використовувати для перевірки використання декількох класів type(obj) in (A, B, C)
Так, ви можете перевірити рівність типів, але замість перерахованого вище використовуйте кілька підстав для управління потоком, якщо ви спеціально не дозволяєте лише цим типам:
isinstance(obj, (A, B, C))
Відмінність, знову ж таки, полягає в тому, що isinstance
підтримує підкласи, які можуть бути замінені для батьківського, не інакше порушуючи програму, властивість, відома як заміна Ліскова.
Ще краще, проте, інвертуйте свої залежності і взагалі не перевіряйте конкретні типи.
Висновок
Отже, оскільки ми хочемо підтримувати підстановку підкласів, у більшості випадків ми хочемо уникати перевірки type
типу та віддавати перевагу перевірці типу isinstance
- якщо вам справді не потрібно знати точний клас екземпляра.
str
іunicode
(де ви можете просто перевіритиbasestring
), ви можете використовувати кортеж для перевірки проти кількох типів. Щоб перевірити, чиsomething
є,int
чиstr
використовуватиisinstance(something, (int, str))
.