Jakie są różnice między type () i isinstance()?

Jakie są różnice między tymi dwoma fragmentami kodu? Użycie type():

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

Używając isinstance():

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()
Author: TylerH, 2009-10-11

6 answers

Podsumowując zawartość innych (już dobrze!) odpowiada, isinstance odpowiada za dziedziczenie (instancja klasy pochodnej jest również instancją klasy bazowej), podczas gdy sprawdzanie równościtype nie (wymaga tożsamości typów i odrzuca instancje podtypów, AKA podklasy).

Normalnie, w Pythonie, chcesz, aby Twój kod obsługiwał dziedziczenie, oczywiście (ponieważ dziedziczenie jest tak przydatne, nie byłoby dobrze zatrzymać kodu używającego twojego!), więc isinstance jest mniej złe niż sprawdzanie tożsamości type S, ponieważ bezproblemowo obsługuje dziedziczenie.

Nie chodzi o to, że isinstance jest dobre, pamiętaj-to po prostu mniej złe niż sprawdzanie równości typów. Normalnym, Pythonicznym, preferowanym rozwiązaniem jest prawie niezmiennie "pisanie kaczek": spróbuj użyć argumentu tak, jakby {[24] } był pewnego pożądanego typu, zrób to w try/except instrukcja wyłapująca wszystkie wyjątki, które mogłyby powstać, gdyby argument nie był w rzeczywistości tego typu (lub jakiegokolwiek innego wpisz ładnie kaczka-naśladując to; -), a w klauzuli except spróbuj czegoś innego (używając argumentu "jakby" to był jakiś inny typ).

basestring jest , jednak dość szczególnym przypadkiem-wbudowanym typem, który istnieje tylko, aby pozwolić Ci używać isinstance (zarówno str, jak i unicode podklasy basestring). Ciągi są sekwencjami (można je zapętlić, indeksować, pokroić, ...), ale generalnie chcesz traktować je jako" skalarne " typy-jest to nieco mało prawdopodobne (ale dość częste stosowanie case), aby traktować wszystkie rodzaje łańcuchów (i może inne typy skalarne, np. te, których nie można zapętlić) w jedną stronę, wszystkie kontenery (listy, zestawy, dicty, ...) w inny sposób, a basestring plus isinstance pomaga Ci to zrobić-ogólna struktura tego idiomu jest czymś w rodzaju:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

Można powiedzieć, że basestring jest abstrakcyjną klasą bazową ("ABC") - nie oferuje żadnej konkretnej funkcjonalności podklas, ale raczej istnieje jako "marker", głównie do użytku z isinstance. Koncepcja jest oczywiście coraz bardziej w Pythonie, ponieważ PEP 3119, który wprowadza uogólnienie, został zaakceptowany i został zaimplementowany począwszy od Pythona 2.6 i 3.0.

PEP wyjaśnia, że podczas gdy ABCs może często zastępować pisanie kaczek, na ogół nie ma dużego nacisku, aby to zrobić (patrz tutaj ). ABCs zaimplementowane w ostatnich wersjach Pythona oferują jednak dodatkowe korzyści: isinstance (i issubclass) może teraz oznaczać więcej niż tylko " [instancję] klasy pochodnej "(w szczególności dowolną klasę może być "zarejestrowany" za pomocą ABC tak, że będzie wyświetlany jako podklasa, a jej instancje jako instancje ABC); a ABCs może również zaoferować dodatkową wygodę rzeczywistym podklasom w bardzo naturalny sposób za pomocą aplikacji wzorców projektowych metody szablonowej (zobacz tutaj i tutaj [[część II]] aby dowiedzieć się więcej na temat TM DP, ogólnie i konkretnie w Pythonie, niezależnie od ABCs).

Aby zapoznać się z podstawową mechaniką obsługi ABC oferowaną w Pythonie 2.6, zobacz tutaj ; dla ich Wersja 3.1, bardzo podobna, zobacz tutaj . W obu wersjach moduł biblioteki standardowej collections (jest to wersja 3.1-bardzo podobna Wersja 2.6, zobacz tutaj ) oferuje kilka przydatnych ABC.

Na potrzeby tej odpowiedzi, kluczową rzeczą do zachowania w ABCs (poza prawdopodobnie bardziej naturalnym miejscem dla funkcjonalności TM DP, w porównaniu do klasycznej alternatywy Pythona dla klas mixin, takich jak UserDict.DictMixin ) jest to, że tworzą isinstance (i issubclass) o wiele bardziej atrakcyjne i wszechobecne (w Pythonie 2.6 i w przyszłości) niż kiedyś (w 2.5 i wcześniej), a zatem, dla kontrastu, sprawdzanie równości typów jest jeszcze gorszą praktyką w ostatnich wersjach Pythona niż wcześniej.

 1034
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-18 20:30:05

Oto dlaczego isinstance jest lepsze niż type:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

W tym przypadku, obiekt ciężarówka jest pojazdem, ale dostaniesz to:

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.

Innymi słowy, isinstance jest prawdą również dla podklas.

Zobacz także: Jak porównać typ obiektu w Pythonie?

 273
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:24

Różnice między isinstance() a type() w Pythonie?

Sprawdzanie typu z

isinstance(obj, Base)

Pozwala na instancje podklas i wiele możliwych baz:

isinstance(obj, (Base1, Base2))

Podczas gdy sprawdzanie typu za pomocą

type(obj) is Base

Obsługuje tylko typ, do którego się odwołuje.


Jako boczna Uwaga, is jest prawdopodobnie bardziej odpowiednia niż

type(obj) == Base

Ponieważ klasy są singletonami.

Unikaj sprawdzania typu-użyj polimorfizmu

W Pythonie, zazwyczaj chcesz zezwolić na dowolny typ argumentów, traktuj go zgodnie z oczekiwaniami, a jeśli obiekt nie będzie zachowywał się zgodnie z oczekiwaniami, spowoduje to odpowiedni błąd. Jest to znane jako polimorfizm, znany również jako pisanie kaczek.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

Jeśli powyższy kod działa, możemy założyć, że nasz argument jest kaczką. W ten sposób możemy przekazać inne rzeczy są rzeczywistymi podtypami kaczki:

function_of_duck(mallard)

Albo to działa jak kaczka:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

I nasz kod wciąż działa.

Są jednak przypadki, w których pożądane jest jawne sprawdzenie typu. Być może masz sensowne rzeczy do zrobienia z różnymi typami obiektów. Na przykład obiekt Panda Dataframe może być zbudowany z rekordów dicts lub. W takim przypadku twój kod musi wiedzieć, jaki rodzaj argumentu otrzymuje, aby mógł prawidłowo go obsłużyć.

Tak więc, aby odpowiedzieć na pytanie:

Różnice między isinstance() a type() w Pythonie?

Pozwól mi aby wykazać różnicę:

type

Powiedz, że musisz zapewnić pewne zachowanie, jeśli twoja funkcja otrzyma określony rodzaj argumentu (wspólny przypadek użycia konstruktorów). Jeśli zaznaczysz Typ taki:

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')

Jeśli spróbujemy przekazać w dict, który jest podklasą dict (Jak powinniśmy być w stanie, jeśli oczekujemy, że nasz kod będzie działał zgodnie z zasadą substytucji Liskowa , to podtypy mogą być zastąpione typami) nasz kod breaks!:

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

Podnosi błąd!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

Ale jeśli użyjemy isinstance, możemy poprzeć zastąpienie Liskowa!:

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')]))

Zwraca OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

Abstrakcyjne Klasy Bazowe

W rzeczywistości, możemy zrobić jeszcze lepiej. collections dostarcza abstrakcyjnych klas bazowych, które wymuszają Minimalne protokoły dla różnych typów. W naszym przypadku, jeśli oczekujemy tylko protokołu Mapping, możemy wykonać następujące czynności, a nasz kod staje się jeszcze bardziej elastyczny:
from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

Odpowiedź skomentuj:

Należy zauważyć, że typ może być używany do sprawdzania wielu klas za pomocą type(obj) in (A, B, C)

Tak, możesz przetestować pod kątem równości typów, ale zamiast powyższego, użyj wielu baz do sterowania przepływem, chyba że wyraźnie zezwalasz tylko na te typy:

isinstance(obj, (A, B, C))

Znowu różnica polega na tym, że isinstance obsługuje podklasy, które można zastąpić rodzicem bez łamania programu w inny sposób, właściwość znana jako Liskov zastępstwo.

Jeszcze lepiej Odwróć zależności i w ogóle nie sprawdzaj konkretnych typów.

Podsumowanie

Ponieważ chcemy wspierać zastępowanie podklas, w większości przypadków chcemy unikać sprawdzania typu za pomocą type i preferować sprawdzanie typu za pomocą isinstance - chyba że naprawdę musisz znać dokładną klasę instancji.

 64
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-26 12:47:58

Ta ostatnia jest preferowana, ponieważ będzie prawidłowo obsługiwać podklasy. W rzeczywistości twój przykład można napisać jeszcze łatwiej, ponieważ drugi parametr isinstance() może być krotką:

if isinstance(b, (str, unicode)):
    do_something_else()

Lub, używając basestring klasy abstrakcyjnej:

if isinstance(b, basestring):
    do_something_else()
 57
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-28 15:51:16

Zgodnie z dokumentacją Pythona oto oświadczenie:

8.15. typy-nazwy typów wbudowanych

Począwszy od Pythona 2.2, wbudowany funkcje fabryczne, takie jak int() i str() są również nazwy dla odpowiednie typy.

Więc isinstance() powinny być preferowane w stosunku do type().

 11
Author: Xinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-24 17:52:55

Dla rzeczywistych różnic, możemy go znaleźć w code, ale nie mogę znaleźć implementacji domyślnego zachowania isinstance().

Jednak możemy uzyskać podobny abc.__ instancecheck _ _ zgodnie z _ _ instancecheck _ _ .

Z góry abc.__instancecheck__, po użyciu testu poniżej:

# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass

# /test/aaa/a.py
import sys
sys.path.append('/test')

from aaa.aa import b
from aa import b as c

d = b()

print(b, c, d.__class__)
for i in [b, c, object]:
    print(i, '__subclasses__',  i.__subclasses__())
    print(i, '__mro__', i.__mro__)
    print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
    print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))

<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False

I get this conclusion, Dla type:

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

Dla isinstance:

# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})

BTW: lepiej nie mieszać use relative and absolutely import, use absolutely import z project_dir( dodany przez sys.path)

 0
Author: Cheney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-10 08:00:00