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()
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.
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?
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()
atype()
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.
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()
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()
istr()
są również nazwy dla odpowiednie typy.
Więc isinstance()
powinny być preferowane w stosunku do type()
.
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
)
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