Jakie są różnice między tymi dwoma fragmentami kodu?
Używanie type()
:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Używanie isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
python
oop
inheritance
types
opat
źródło
źródło
str
iunicode
gdzie można to po prostu sprawdzićbasestring
), możesz użyć krotki do sprawdzania wielu typów. Aby sprawdzić, czysomething
jestint
lubstr
użyjisinstance(something, (int, str))
.Odpowiedzi:
Podsumowując treść innych (już dobrych!) Odpowiedzi,
isinstance
uwzględnia dziedziczenie (instancja klasy pochodnej jest również instancją klasy podstawowej), a sprawdzanie równościtype
nie (wymaga identyczności typów i odrzuca instancje podtypów, podklasy AKA).Zwykle w Pythonie chcesz, aby Twój kod obsługiwał dziedziczenie, oczywiście (ponieważ dziedziczenie jest tak przydatne, byłoby źle, aby przestać używać kodu z twojego!), Więc
isinstance
jest mniej złe niż sprawdzanie tożsamościtype
s, ponieważ płynnie obsługuje dziedzictwo.Pamiętaj, że
isinstance
to nie jest dobre - jest po prostu mniej złe niż sprawdzanie równości typów. Normalnym, Pythonicznym, preferowanym rozwiązaniem jest prawie zawsze „pisanie kaczki”: spróbuj użyć argumentu tak, jakby był z określonego pożądanego typu, zrób to w instrukcjitry
/except
wychwytując wszystkie wyjątki, które mogłyby powstać, gdyby argument nie był w rzeczywistości type (lub jakikolwiek inny typ ładnie naśladujący to kaczkę ;-), a wexcept
klauzuli spróbuj czegoś innego (używając argumentu „jak gdyby” był innego typu).basestring
jest jednak dość szczególnym przypadkiem - wbudowanym typem, który istnieje tylko po to, abyś mógł używaćisinstance
(zarówno podklasy, jakstr
iunicode
podklasybasestring
). Ciągi są sekwencjami (można je nad nimi zapętlać, indeksować, pokroić, ...), ale generalnie chcesz traktować je jako typy „skalarne” - jest to nieco niewygodne (ale dość częsty przypadek użycia) do traktowania wszystkich rodzajów ciągi (i być może inne typy skalarne, tj. takie, których nie można zapętlić) w jeden sposób, wszystkie kontenery (listy, zestawy, dykty, ...) w inny sposób, abasestring
plusisinstance
pomaga to zrobić - ogólna struktura tego idiom jest jak:Można powiedzieć, że
basestring
jest to Abstrakcyjna Klasa Podstawowa („ABC”) - nie oferuje konkretnych funkcji dla podklas, ale istnieje raczej jako „marker”, głównie do użytku zisinstance
. Koncepcja jest oczywiście coraz popularniejsza w Pythonie, ponieważ PEP 3119 , który wprowadza uogólnienie, został zaakceptowany i został wdrożony począwszy od Pythona 2.6 i 3.0.PEP wyjaśnia, że chociaż ABC często zastępuje pisanie kaczką, generalnie nie ma na to dużej presji (patrz tutaj ). ABC zaimplementowane w najnowszych wersjach Pythona oferują jednak dodatkowe korzyści:
isinstance
(iissubclass
) mogą teraz oznaczać więcej niż tylko „[instancję] klasy pochodnej” (w szczególności każdą klasę można „zarejestrować” w ABC, aby była pokaż jako podklasę, a jej instancje jako instancje ABC); i ABC mogą również oferować dodatkową wygodę dla rzeczywistych podklas w bardzo naturalny sposób dzięki aplikacjom wzorcowym do projektowania szablonów (patrz tutaj i tutaj [[część II]], aby uzyskać więcej informacji na temat TM DP, ogólnie, a konkretnie w Pythonie, niezależnie od ABC) .Podstawowe mechanizmy obsługi ABC oferowane w Pythonie 2.6 znajdują się tutaj ; ich bardzo podobna wersja 3.1, patrz tutaj . W obu wersjach standardowe kolekcje modułów bibliotecznych (to jest wersja 3.1 - bardzo podobna wersja 2.6, patrz tutaj ) oferuje kilka przydatnych ABC.
Dla celów tej odpowiedzi kluczową rzeczą do zapamiętania na temat ABC (poza prawdopodobnie bardziej naturalnym rozmieszczeniem dla funkcji TM DP, w porównaniu do klasycznej alternatywy Python dla klas mixin, takich jak UserDict.DictMixin ) jest to, że tworzą
isinstance
(iissubclass
) znacznie więcej atrakcyjne i wszechobecne (w Pythonie 2.6 i późniejszych) niż kiedyś (w wersji 2.5 i wcześniejszych), a tym samym sprawiają, że sprawdzanie równości typów jest jeszcze gorszą praktyką w najnowszych wersjach Pythona niż kiedyś.źródło
Oto przykład, w którym
isinstance
osiąga coś,type
czego nie można:w tym przypadku obiektem ciężarówki jest pojazd, ale otrzymasz to:
Innymi słowy,
isinstance
dotyczy to również podklas.Zobacz także: Jak porównać typ obiektu w Pythonie?
źródło
type
jest przestarzałe, użyjisinstance
zamiast niego”. na przykład chciałem dokładnietype()
sprawdzić, ale z tego powodu zostałem wprowadzony w błąd przez krótki czas (i musiałem trochę debugować).type()
a nieisinstance()
. Jedno nie jest lepsze; są do różnych rzeczy.Sprawdzanie typu za pomocą
pozwala na wystąpienia podklas i wielu możliwych baz:
podczas gdy kontrola typu za pomocą
obsługuje tylko wskazany typ.
Jako sidenote,
is
jest prawdopodobnie bardziej odpowiednie niżponieważ zajęcia są singletonami.
Unikaj sprawdzania typu - używaj polimorfizmu (pisanie kaczką)
W Pythonie zazwyczaj chcesz zezwolić na dowolny typ argumentów, traktować go zgodnie z oczekiwaniami, a jeśli obiekt nie zachowuje się zgodnie z oczekiwaniami, wygeneruje odpowiedni błąd. Jest to znane jako polimorfizm, znany również jako pisanie kaczek.
Jeśli powyższy kod działa, możemy założyć, że nasz argument jest kaczką. Możemy więc przekazać, że inne rzeczy to rzeczywiste podtypy kaczek:
lub które działają jak kaczka:
a nasz kod nadal działa.
Istnieją jednak przypadki, w których pożądane jest jawne sprawdzenie typu. Być może masz sensowne rzeczy związane z różnymi typami obiektów. Na przykład obiekt Pandas Dataframe można zbudować z nagrań lub nagrań. W takim przypadku Twój kod musi wiedzieć, jaki typ argumentu otrzymuje, aby mógł poprawnie go obsłużyć.
Tak więc, aby odpowiedzieć na pytanie:
Różnice między Pythonem
isinstance()
i pomiędzy nimitype()
?Pozwól mi zademonstrować różnicę:
type
Powiedz, że musisz zapewnić określone zachowanie, jeśli twoja funkcja otrzyma pewien rodzaj argumentu (częsty przypadek użycia dla konstruktorów). Jeśli zaznaczysz taki typ:
Jeśli spróbujemy przekazać dyktandę, która jest podklasą
dict
(tak jak powinniśmy, jeśli oczekujemy, że nasz kod będzie zgodny z zasadą podstawienia Liskowa , że podtypy można zastąpić typami), nasz kod się zepsuje !:wywołuje błąd!
isinstance
Ale jeśli skorzystamy
isinstance
, możemy wesprzeć zastąpienie Liskowa !:zwroty
OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Abstrakcyjne klasy podstawowe
W rzeczywistości możemy zrobić jeszcze lepiej.
collections
zapewnia abstrakcyjne klasy podstawowe, które egzekwują minimalne protokoły dla różnych typów. W naszym przypadku, jeśli oczekujemy tylkoMapping
protokołu, możemy wykonać następujące czynności, a nasz kod staje się jeszcze bardziej elastyczny:Odpowiedź na komentarz:
Tak, możesz przetestować równość typów, ale zamiast powyższego użyj wielu zasad dla przepływu sterowania, chyba że zezwalasz tylko na te typy:
Znowu różnica polega na tym, że
isinstance
obsługuje podklasy, które można podstawić dla elementu nadrzędnego, nie przerywając w inny sposób programu, właściwość zwaną podstawieniem Liskov.Co więcej, odwróć swoje zależności i nie sprawdzaj w ogóle konkretnych typów.
Wniosek
Ponieważ chcemy wspierać zastępowanie podklas, w większości przypadków chcemy unikać sprawdzania
type
typów i wolimy sprawdzanie typów za pomocąisinstance
- chyba że naprawdę potrzebujesz znać dokładną klasę instancji.źródło
isinstance(instance, y)
i używaszfrom v.w.x import y
, i importujesz ten czek, ale gdy utworzysz instancjęinstance
, użyjeszfrom x import y
zamiast tego, w jaki sposób y zostało zaimportowane w pliku twoja_module.py, kontrola isinstance zakończy się niepowodzeniem, nawet jeśli jest to ta sama klasa.Ten ostatni jest preferowany, ponieważ będzie poprawnie obsługiwał podklasy. W rzeczywistości twój przykład można napisać jeszcze łatwiej, ponieważ
isinstance()
drugim parametrem może być krotka:lub za pomocą
basestring
klasy abstrakcyjnej:źródło
Zgodnie z dokumentacją Pythona tutaj jest stwierdzenie:
Więc
isinstance()
powinno być lepsze niżtype()
.źródło
Praktyczną różnicą w użyciu jest sposób, w jaki obsługują
booleans
:True
iFalse
to tylko słowa kluczowe, to znaczy, że1
i0
w Pythonie. A zatem,i
oba wracają
True
. Oba booleany są wystąpieniem liczby całkowitej.type()
jest jednak bardziej sprytny:zwraca
False
.źródło
Dla prawdziwych różnic możemy go znaleźć
code
, ale nie mogę znaleźć implementacji domyślnego zachowaniaisinstance()
.Możemy jednak uzyskać podobny abc .__ instancecheck__ zgodnie z __instancecheck__ .
Z góry
abc.__instancecheck__
, po zastosowaniu testu poniżej:Mam taki wniosek, ponieważ
type
:Dla
isinstance
:BTW: lepiej nie mieszać użycia
relative and absolutely import
, użyjabsolutely import
z project_dir (dodane przezsys.path
)źródło