Care sunt diferențele dintre aceste două fragmente de cod? Folosind tipul()`:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Folosind isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
Pentru a rezuma conținutul de alte (deja!) răspunsuri, isinstance
satisfacă pentru moștenirea (o instanță a unei clase derivate is an exemplu de o clasă de bază, de asemenea), în timp ce verificarea pentru egalitatea de " tip " nu (se cere identitate de tipuri și respinge cazuri de subtipuri, AKA subclase).
În mod normal, în Python, vrei codul pentru a sprijini moștenire, desigur (din moștenire este atât de la îndemână, ar fi rău pentru a opri folosind codul tău de folosind-o!), deci isinstance
este mai puțin rău decât verificarea identității de tip e pentru că-l sprijină perfect moștenire.
L's nu isinstance
este good, tine minte—l's doar less bad decât verificarea egalității de tipuri. Normal, Pythonic, soluție preferată este aproape invariabil "duck typing": încercați să utilizați argumentul as if a fost de un anumit tip dorit, fă-o într-o "încerca" /afară
declarație de capturare toate excepțiile care ar putea apărea dacă argumentul nu a fost de fapt de acel tip (sau orice alt tip frumos rață-imitarea ea;-), și în afară de clauza, încercați altceva (folosind argumentul "ca daca" a fost de un alt tip).
basestring
e, cu toate acestea, destul de un caz special—o interna tip care există doar să utilizați isinstance
(ambele str
și unicode
subclasa basestring
). Siruri de caractere sunt secvențe (ai putea bucla peste ele, să le indice, felie-le, ...), dar, în general, vreau să le trateze ca "scalar" tipuri—l's oarecum incovenient (dar rezonabil o utilizare frecventă caz) pentru a trata toate tipurile de siruri de caractere (și, poate, alte tipuri scalare, de exemplu, acelea't buclă pe) într-un fel, toate containerele (liste, seturi, previziuni, ...) într-un alt mod, și basestring "plus" isinstance
te ajută să faci asta—structura de ansamblu a acestui idiom este ceva de genul:
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
Ai putea spune că basestring
este un Abstract Bază Class ("ABC")—nu oferă beton functionalitate la subclase, ci mai degrabă există ca un "marker", în principal pentru utilizarea cu isinstance
. Conceptul este în mod evident în creștere în Python, deoarece PEP 3119, care prezintă o generalizare a acesteia, a fost acceptată și a fost pusă în aplicare începând cu Python 2.6 si 3.0.
PEP face clar faptul că, în timp ce Abc-ul poate de multe ori un substitut pentru duck typing, nu există în general nici o presiune mare pentru a face asta (a se vedea aici). Abc-ul implementat în ultimii Python versiunile cu toate acestea, ofera un plus de bunatati: isinstance "(și " issubclass
) poate acum înseamnă mai mult decât doar "[un exemplu] o clasă derivată" (în special, orice clasa poate fi "înregistrat" cu un ABC, astfel încât acesta va arata ca o subclasa, iar cazuri ca instanțe ale ABC); și Abc-ul poate, de asemenea, oferă un plus de confort la real subclase într-un mod foarte natural prin Metoda Template design model de aplicații (a se vedea aici și aici [[partea II]] pentru mai multe pe TM PD, în general, și în special în Python, independent de Abc-ul).
Pentru mecanica de bază de ABC sprijinul oferit în Python 2.6, a se vedea aici; pentru versiunea 3.1, foarte similare, a se vedea aici. În ambele versiuni, standard library module colecții (ca's versiunea 3.1—pentru foarte similare 2.6 versiune, a se vedea aici) oferă mai multe Abc-ul util.
Pentru scopul acestui răspuns, cel mai important lucru de a păstra despre Abc-ul (dincolo de o, fără îndoială, mai natural de plasament pentru TM DP functionality, comparativ cu cel clasic Python alternative de mixin clase, cum ar fi UserDict.DictMixin) este că ei fac isinstance "(și " issubclass`) mult mai atractiv și omniprezent (în Python 2.6 și merge înainte), decât au folosit pentru a fi (în 2,5 și înainte), și, prin urmare, prin contrast, face verificarea de tip egalitate și mai practică în ultimii Python versiuni decât este deja folosit pentru a fi.
Aici's un exemplu unde isinstance` atinge ceva care " tip " nu se poate:
class Vehicle:
pass
class Truck(Vehicle):
pass
în acest caz, un camion obiect este un Vehicul, dar'll a obține acest lucru:
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.
Cu alte cuvinte, `isinstance este adevărat pentru subclase, de asemenea.
Vezi, de asemenea: https://stackoverflow.com/q/707674/1341006
Diferențele între
isinstance () " și " de tip()
în Python?
Tip-verificarea cu
isinstance(obj, Base)
permite pentru cazuri de subclase și mai multe baze posibile:
isinstance(obj, (Base1, Base2))
întrucât tip de verificare cu
type(obj) is Base
acceptă numai tipul de referință.
Ca o paranteză, "este" este probabil mai adecvată decât
type(obj) == Base
deoarece cursurile sunt burlaci.
În Python, de obicei, doriți, pentru a permite orice tip de argumentele tale, tratează-l așa cum era de așteptat, și în cazul în care obiectul nu't se comporta cum era de așteptat, acesta va ridica o eroare corespunzător. Acest lucru este cunoscut sub numele de polimorfism, de asemenea, cunoscut sub numele de rață-dactilografiere.
def function_of_duck(duck):
duck.quack()
duck.swim()
Dacă codul de mai sus funcționează, putem presupune că argumentul nostru este o rață. Astfel, putem trece la alte lucruri sunt reale sub-tipuri de rață:
function_of_duck(mallard)
sau care funcționează ca o rață:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
și codul nostru încă mai funcționează.
Cu toate acestea, există unele cazuri în care este de dorit să se în mod explicit tipul de verificare. Poate că aveți lucrurile sensibile de-a face cu diferite tipuri de obiecte. De exemplu, Panda Dataframe obiect poate fi construit din dicts sau înregistrări. Într-un asemenea caz, codul trebuie să știe ce tip de argument este obtinerea, astfel încât acesta poate l ocupe în mod corespunzător.
Deci, pentru a răspunde la întrebarea:
isinstance () " și " de tip()
în Python?Permiteți-mi să demonstreze diferența:
Spun aveți nevoie pentru a asigura un anumit comportament dacă funcția devine un anumit tip de argument (un caz de utilizare pentru constructori). Dacă tu a verifica pentru tip de genul asta:
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')
Dacă am încerca să treacă într-un dict că este o subclasă a dict
(cum ar trebui să fie în măsură să, dacă ne-am're așteaptă codul nostru să urmeze principiul de Liskov Substituție, care subtipuri poate fi înlocuit de tipuri) codul nostru de rupe!:
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
ridică o eroare!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a dict
isinstance
Dar dacă vom folosi isinstance
, putem sprijini Liskov de Substituție!:
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')]))
se întoarce OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
În fapt, putem face chiar mai bine. "colectii" oferă Abstracte Clase de Bază care intareasca minim protocoale pentru diverse tipuri. În cazul nostru, dacă ne așteptăm doar la "Cartografiere" protocol, putem face următoarele, și codul nostru devine și mai flexibil:
from collections import Mapping
def foo(a_dict):
if not isinstance(a_dict, Mapping):
raise ValueError('argument must be a dict')
return a_dict
Acesta ar trebui să fie remarcat faptul că tipul poate fi folosit pentru a verifica împotriva mai multor clase folosind
tip(obj) în (a, B, C)
Da, puteți testa pentru egalitatea de tipuri, dar în loc de cele de mai sus, de a folosi mai multe baze pentru controlul fluxului, dacă nu sunt în mod special care să permită numai acele tipuri:
isinstance(obj, (A, B, C))
Diferența, din nou, este că isinstance
sprijină subclase, care poate fi înlocuit de părinte fără altfel de rupere program, o proprietate cunoscută ca Liskov substitution.
Chiar mai bine, deși, acopera-ti dependențe și don't verificați pentru tipuri specifice, la toate.
Deci de vreme ce doresc să sprijine substituirea subclase, în cele mai multe cazuri, ne-o dorim pentru a evita tip de verificare cu " tip " și preferă tip de verificare cu isinstance` - dacă nu într-adevăr nevoie să știu precis clasă de o instanță.
Acesta din urmă este de preferat, pentru că se va ocupa de subclase în mod corespunzător. În fapt, exemplul tau poate fi scris chiar mai ușor, deoarece isinstance()
's de-al doilea parametru poate fi un tuplu:
if isinstance(b, (str, unicode)):
do_something_else()
sau, folosind basestring
clasă abstractă:
if isinstance(b, basestring):
do_something_else()
Potrivit python documentație aici este o declarație:
8.15. tipuri — de-Nume, pentru built-in tipuri
Începând din Python 2.2, built-in fabrica de funcții, cum ar fi
int()
șistr()
sunt, de asemenea, nume de tipurile corespunzătoare.
Deci isinstance()
ar trebui să fie de preferat peste type()
.
O utilizare practică diferența este modul în care acestea se ocupe de boolean
:
"Adevărat" și "Fals" sunt doar cuvinte cheie, care înseamnă " 1 " și " 0 " în python. Astfel,
isinstance(Adevărat, int)
și
isinstance(False, int)
ambele returna "True". Ambele booleene sunt un exemplu de un număr întreg. tip()
, cu toate acestea, este mult mai inteligent:
tip(True) == int
returneaza "False".
Pentru diferențele reale, putem găsi în "cod", dar nu pot't găsi aplicare de comportamentul implicit al isinstance()
.
Cu toate acestea, putem obține unul similar abc.__instancecheck__ potrivit __instancecheck__.
De sus abc.__instancecheck__
, după folosind testul de mai jos:
# 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 a lua această concluzie, Pentru "tip":
# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__
Pentru 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: mai bine să nu se amestece folosesc relativ și absolut de import, utilizat
absolut importdin project_dir( adăugat de
sys.calea`)