Различия между isinstance()
и type()
в Python?
Проверка типа с
isinstance(obj, Base)
допускает экземпляры подклассов и несколько возможных баз:
isinstance(obj, (Base1, Base2))
тогда как проверка типа с
type(obj) is Base
поддерживает только указанный тип.
В качестве sidenote, is
вероятно, более подходящим, чем
type(obj) == Base
потому что классы синглтоны.
Избегайте проверки типов - используйте Polymorphism (duck-typing)
В 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)
и наш код все еще работает.
Однако в некоторых случаях желательно явно проверять тип. Возможно, вы имеете дело с разными типами объектов. Например, объект Dataframe Pandas может быть создан из диктовок или записей. В таком случае ваш код должен знать, какой тип аргумента он получает, чтобы он мог правильно с ним справиться.
Итак, чтобы ответить на вопрос:
Различия между isinstance()
и type()
в Python?
Позвольте мне продемонстрировать разницу:
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, который является подклассом 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))
.