Резюмируя содержание других (уже хороших!) ответов, isinstance учитывает наследование (экземпляр производного класса также является экземпляром базового класса), в то время как проверка на равенство type этого не делает (требует идентичности типов и отклоняет экземпляры подтипов, ТАКЖЕ известные КАК подклассы).
Обычно в Python вы, конечно, хотите, чтобы ваш код поддерживал наследование (поскольку наследование настолько удобно, было бы плохо запретить коду, использующему ваш, использовать его!), Так что isinstance это менее плохо, чем проверка идентичности type s, потому что он беспрепятственно поддерживает наследование.
Дело не в том, что это isinstanceхорошо, имейте в виду — это просто менее плохо, чем проверка равенства типов. Обычным, питоновским, предпочтительным решением почти всегда является "утиный ввод": попробуйте использовать аргумент, как если бы он был определенного желаемого типа, сделайте это в операторе try/except , перехватывающем все исключения, которые могли возникнуть, если аргумент на самом деле не был этого типа (или любого другого типа, который хорошо имитирует его;-), и в except предложении попробуйте что-нибудь еще (используя аргумент "как если бы" он был какого-то другого типа).
basestringэто, однако, совершенно особый случай — встроенный тип, который существует только для того, чтобы вы могли использовать isinstance (оба str и unicode подкласс basestring). Строки представляют собой последовательности (вы можете перебирать их, индексировать, нарезать, ...), Но обычно вы хотите рассматривать их как "скалярные" типы — это несколько неудобно (но достаточно частый вариант использования) обрабатывать все виды строк (и, возможно, другие скалярные типы, т. Е. Те, которые вы не можете использовать в цикле) одним способом, все контейнеры (списки, наборы, dicts, ...) другим способом, и basestring plus isinstance поможет вам сделать это — общая структура этой идиомы это что-то вроде:
Можно сказать, что basestring это абстрактный базовый класс ("ABC") — он не предлагает конкретной функциональности подклассам, а скорее существует как "маркер", в основном для использования с isinstance. Очевидно, что концепция растет в Python, поскольку PEP 3119, который представляет ее обобщение, был принят и реализован, начиная с Python 2.6 и 3.0.
PEP дает понять, что, хотя ABCs часто может заменить утиный ввод, как правило, нет большого давления для этого (см. Здесь ). Однако ABCS, реализованные в последних версиях Python, предлагают дополнительные преимущества: isinstance (и issubclass) теперь может означать больше, чем просто "[экземпляр] производного класса" (в частности, любой класс может быть "зарегистрирован" с помощью ABC, чтобы он отображался как подкласс, а его экземпляры - как экземпляры ABC); и ABCS также может предложить дополнительное удобство для реальных подклассов очень естественным образом с помощью шаблонных приложений для разработки методов шаблонов (см. Здесь и здесь [ [часть II]] подробнее о TM DP, в целом и конкретно в Python, независимо от ABCs).
О базовой механике поддержки ABC, предлагаемой в Python 2.6, смотрите Здесь; об их версии 3.1, очень похожей, смотрите Здесь. В обеих версиях коллекции стандартных библиотечных модулей (это версия 3.1 — для очень похожей версии 2.6 смотрите Здесь) предлагает несколько полезных азбук.
Для целей этого ответа необходимо сохранить ключевую информацию об ABCs (помимо, возможно, более естественного размещения функциональности TM DP по сравнению с классической альтернативой Python в виде смешанных классов, таких как UserDict .DictMixin) заключается в том, что они делают isinstance (и issubclass) намного более привлекательными и распространенными (в Python 2.6 и в дальнейшем), чем они были раньше (в 2.5 и ранее), и, следовательно, напротив, делают проверку равенства типов еще худшей практикой в последних версиях Python, чем это уже было раньше.
Ответ 2
Вот пример, в котором isinstance достигается то, что type невозможно:
classVehicle: pass
classTruck(Vehicle): pass
В этом случае Truck объектом является Vehicle, но вы получите следующее:
isinstance(Vehicle(), Vehicle) # returns True type(Vehicle()) == Vehicle # returns True isinstance(Truck(), Vehicle) # returns True type(Truck()) == Vehicle # returns False, and this probably won't be what you want.
Другими словами, isinstance() верно и для подклассов.
допускает экземпляры подклассов и несколько возможных баз:
isinstance(obj, (Base1, Base2))
в то время как проверка типа с помощью
type(obj) is Base
поддерживает только указанный тип.
В качестве дополнительного примечания, is вероятно, более уместно, чем
type(obj) == Base
потому что классы являются одиночными.
Избегайте проверки типов - используйте полиморфизм (утиный ввод)
В Python обычно вы хотите разрешить любой тип для своих аргументов, обрабатывать его как ожидалось, и если объект ведет себя не так, как ожидалось, это вызовет соответствующую ошибку. Это известно как полиморфизм, также известный как утиный ввод.
Если приведенный выше код работает, мы можем предположить, что нашим аргументом является duck . Таким образом, мы можем передать другие вещи, являющиеся реальными подтипами duck:
Однако в некоторых случаях желательно явно проверять тип. Возможно, у вас есть разумные способы работы с разными типами объектов. Например, объект фрейма данных Pandas может быть сконструирован из dicts или записей. В таком случае ваш код должен знать, какой тип аргумента он получает, чтобы он мог правильно его обработать.
Итак, чтобы ответить на вопрос:
Различия между isinstance() и type() в Python?
Позвольте мне продемонстрировать разницу:
type
Допустим, вам нужно обеспечить определенное поведение, если ваша функция получает аргумент определенного типа (обычный вариант использования конструкторов). Если вы проверяете тип следующим образом:
deffoo(data): '''accepts a dict to construct something, string support in future''' iftype(data) isnotdict: # we're only going to test for dicts for now raise ValueError('only dicts are supported for now')
Если мы попытаемся передать dict, который является подклассом dict (что мы должны иметь возможность, если мы ожидаем, что наш код будет следовать принципу подстановки Лискова, что подтипы могут быть заменены типами), наш код сломается!:
На самом деле, мы можем сделать еще лучше. collections предоставляет абстрактные базовые классы, которые применяют минимальные протоколы для различных типов. В нашем случае, если мы ожидаем только Mapping протокол, мы можем сделать следующее, и наш код станет еще более гибким:
from collections import Mapping
deffoo(a_dict): ifnotisinstance(a_dict, Mapping): raise ValueError('argument must be a dict') return a_dict
Ответ на комментарий:
Следует отметить, что type можно использовать для проверки на соответствие нескольким классам с помощью type(obj) in (A, B, C)
Да, вы можете проверить равенство типов, но вместо приведенного выше используйте несколько баз для потока управления, если только вы специально не разрешаете только эти типы:
isinstance(obj, (A, B, C))
Разница, опять же, в том, что isinstance поддерживает подклассы, которые могут быть заменены родительскими без нарушения работы программы иным образом, свойство, известное как подстановка по Лискову.
Однако еще лучше инвертировать свои зависимости и вообще не проверять наличие определенных типов.
Заключение
Итак, поскольку мы хотим поддерживать замену подклассов, в большинстве случаев мы хотим избежать проверки типов с помощью type и предпочитаем проверку типов с помощью isinstance - если вам действительно не нужно знать точный класс экземпляра.
Ответ 4
Последнее предпочтительнее, потому что оно будет правильно обрабатывать подклассы. Фактически, ваш пример может быть написан даже проще, потому что isinstance()вторым параметром может быть кортеж: