Różnice między Pythonem isinstance()
i pomiędzy nimi type()
?
Sprawdzanie typu za pomocą
isinstance(obj, Base)
pozwala na wystąpienia podklas i wielu możliwych baz:
isinstance(obj, (Base1, Base2))
podczas gdy kontrola typu za pomocą
type(obj) is Base
obsługuje tylko wskazany typ.
Jako sidenote, is
jest prawdopodobnie bardziej odpowiednie niż
type(obj) == Base
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.
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ą. Możemy więc przekazać, że inne rzeczy to rzeczywiste podtypy kaczek:
function_of_duck(mallard)
lub które działają jak kaczka:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
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 nimi type()
?
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:
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ć 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 !:
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
wywołuje 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 skorzystamy isinstance
, możemy wesprzeć 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')]))
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 tylko Mapping
protokołu, 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ź na komentarz:
Należy zauważyć, że typ może być używany do sprawdzania przy użyciu wielu klas type(obj) in (A, B, C)
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:
isinstance(obj, (A, B, C))
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.
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))
.