Was sind die Unterschiede zwischen diesen beiden Codefragmenten?
Verwenden von type()
:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Verwenden von isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
python
oop
inheritance
types
Abt
quelle
quelle
str
undunicode
(wo Sie nur prüfen könnenbasestring
), können Sie ein Tupel zum Prüfen auf mehrere Typen verwenden. Um zu überprüfen, ob essomething
istint
oderstr
verwendenisinstance(something, (int, str))
.Antworten:
Um den Inhalt anderer (bereits guter!) Antworten zusammenzufassen, wird
isinstance
die Vererbung berücksichtigt (eine Instanz einer abgeleiteten Klasse ist auch eine Instanz einer Basisklasse), während auf Gleichheit geprüfttype
wird (dies erfordert die Identität von Typen und lehnt Instanzen ab) von Subtypen, AKA-Unterklassen).Normalerweise möchten Sie in Python natürlich, dass Ihr Code die Vererbung unterstützt (da die Vererbung so praktisch ist, wäre es schlecht, die Verwendung Ihres Codes zu verhindern!), Also
isinstance
weniger schlecht als die Überprüfung der Identität vontype
s, da sie nahtlos unterstützt Erbe.Es ist nicht das
isinstance
ist gut , wohlgemerkt-es ist nur weniger schlecht als Gleichheit der Arten zu überprüfen. Die normale, pythonische, bevorzugte Lösung ist fast immer "Ententypisierung": Versuchen Sie, das Argument so zu verwenden, als ob es von einem bestimmten gewünschten Typ wäre, und führen Sie es in einertry
/except
-Anweisung aus, wobei alle Ausnahmen erfasst werden, die auftreten könnten, wenn das Argument nicht tatsächlich vorhanden wäre Geben Sie ein (oder einen anderen Typ, der es gut nachahmt ;-), undexcept
versuchen Sie in der Klausel etwas anderes (mit dem Argument "als ob" es von einem anderen Typ wäre).basestring
Dies ist jedoch ein ganz besonderer Fall - ein integrierter Typ, der nur zur Verwendung durch Sieisinstance
(sowohlstr
als auchunicode
Unterklassebasestring
) vorhanden ist. Strings sind Sequenzen (Sie können sie durchlaufen, indizieren, in Scheiben schneiden, ...), aber Sie möchten sie im Allgemeinen als "skalare" Typen behandeln - es ist etwas unpraktisch (aber ein ziemlich häufiger Anwendungsfall), alle Arten von zu behandeln Zeichenfolgen (und möglicherweise andere Skalartypen, dh solche, auf denen Sie keine Schleife ausführen können) auf eine Weise, alle Container (Listen, Mengen, Diktate usw.) auf eine andere Weise undbasestring
plusisinstance
helfen Ihnen dabei - die Gesamtstruktur davon Redewendung ist so etwas wie:Man könnte sagen, dass dies
basestring
eine abstrakte Basisklasse ("ABC") ist - sie bietet Unterklassen keine konkrete Funktionalität, sondern existiert als "Marker", hauptsächlich zur Verwendung mitisinstance
. Das Konzept in Python wächst offensichtlich, da PEP 3119 , das eine Verallgemeinerung einführt, akzeptiert wurde und ab Python 2.6 und 3.0 implementiert wurde.Das PEP macht deutlich, dass ABCs zwar häufig die Ententypisierung ersetzen können, dies jedoch im Allgemeinen keinen großen Druck darstellt (siehe hier ). ABCs, wie sie in neueren Python-Versionen implementiert wurden, bieten jedoch zusätzliche Extras:
isinstance
(undissubclass
) können jetzt mehr als nur "[eine Instanz] einer abgeleiteten Klasse" bedeuten (insbesondere kann jede Klasse bei einem ABC "registriert" werden, so dass dies der Fall ist show als Unterklasse und ihre Instanzen als Instanzen des ABC); und ABCs können auch tatsächlichen Unterklassen auf sehr natürliche Weise über Entwurfsmusteranwendungen für Vorlagenmethoden zusätzlichen Komfort bieten (siehe hier und hier [[Teil II]] für weitere Informationen zum TM DP im Allgemeinen und speziell in Python, unabhängig von ABCs). .Die zugrunde liegenden Mechanismen der ABC-Unterstützung, wie sie in Python 2.6 angeboten werden, finden Sie hier . Für ihre Version 3.1, sehr ähnlich, siehe hier . In beiden Versionen Standard - Bibliothek - Modul Sammlungen (das ist die Version 3.1-für die sehr ähnliche Version 2.6 finden Sie hier ) bietet einige nützlichen ABCs.
Für diese Antwort ist es wichtig, ABCs beizubehalten (abgesehen von einer wohl natürlicheren Platzierung der TM DP-Funktionalität im Vergleich zur klassischen Python-Alternative von Mixin-Klassen wie UserDict.DictMixin ), dass sie viel mehr machen
isinstance
(undissubclass
) attraktiver und allgegenwärtiger (in Python 2.6 und in Zukunft) als früher (in 2.5 und früher), und daher ist die Überprüfung der Typgleichheit in neueren Python-Versionen im Gegensatz dazu bereits eine noch schlechtere Praxis als früher.quelle
Hier ist ein Beispiel, wo
isinstance
etwas erreicht wird,type
das nicht kann:In diesem Fall ist ein LKW-Objekt ein Fahrzeug, aber Sie erhalten Folgendes:
Mit anderen Worten,
isinstance
gilt auch für Unterklassen.Siehe auch: Wie vergleiche ich den Typ eines Objekts in Python?
quelle
type
veraltet ist,isinstance
stattdessen verwenden". Ich wollte zum Beispiel genautype()
nachsehen, wurde aber aus diesem Grund für kurze Zeit in die Irre geführt (und musste ein wenig debuggen).type()
und nichtisinstance()
. Man ist nicht besser; Sie sind für verschiedene Dinge.Typprüfung mit
ermöglicht Instanzen von Unterklassen und mehrere mögliche Basen:
wohingegen Typprüfung mit
unterstützt nur den Typ, auf den verwiesen wird.
Als Nebenbemerkung
is
ist wahrscheinlich angemessener alsweil Klassen Singletons sind.
Vermeiden Sie die Typprüfung - verwenden Sie Polymorphismus (Ententypisierung)
In Python möchten Sie normalerweise einen beliebigen Typ für Ihre Argumente zulassen, ihn wie erwartet behandeln. Wenn sich das Objekt nicht wie erwartet verhält, wird ein entsprechender Fehler ausgegeben. Dies ist als Polymorphismus bekannt, auch als Ententypisierung bekannt.
Wenn der obige Code funktioniert, können wir davon ausgehen, dass unser Argument eine Ente ist. So können wir in anderen Dingen tatsächliche Untertypen von Enten übergeben:
oder das funktioniert wie eine Ente:
und unser Code funktioniert immer noch.
Es gibt jedoch einige Fälle, in denen eine explizite Typprüfung wünschenswert ist. Vielleicht haben Sie vernünftige Dinge mit verschiedenen Objekttypen zu tun. Beispielsweise kann das Pandas Dataframe-Objekt aus Diktaten oder Datensätzen erstellt werden. In einem solchen Fall muss Ihr Code wissen, welche Art von Argument er erhält, damit er richtig damit umgehen kann.
Um die Frage zu beantworten:
Unterschiede zwischen
isinstance()
undtype()
in Python?Lassen Sie mich den Unterschied demonstrieren:
type
Angenommen, Sie müssen ein bestimmtes Verhalten sicherstellen, wenn Ihre Funktion eine bestimmte Art von Argument erhält (ein häufiger Anwendungsfall für Konstruktoren). Wenn Sie nach einem solchen Typ suchen:
Wenn wir versuchen, ein Diktat zu übergeben, das eine Unterklasse von
dict
(wie wir sollten, wenn wir erwarten, dass unser Code dem Prinzip der Liskov-Substitution folgt , dass Subtypen durch Typen ersetzt werden können), bricht unser Code!:löst einen Fehler aus!
isinstance
Aber wenn wir verwenden
isinstance
, können wir Liskov Substitution unterstützen!:kehrt zurück
OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Abstrakte Basisklassen
In der Tat können wir es noch besser machen.
collections
bietet abstrakte Basisklassen, die minimale Protokolle für verschiedene Typen erzwingen. Wenn wir in unserem Fall nur dasMapping
Protokoll erwarten , können wir Folgendes tun, und unser Code wird noch flexibler:Antwort auf Kommentar:
Ja, Sie können die Gleichheit der Typen testen, aber anstelle der oben genannten verwenden Sie die mehreren Basen für den Kontrollfluss, es sei denn, Sie erlauben ausdrücklich nur diese Typen:
Der Unterschied besteht wiederum darin, dass
isinstance
Unterklassen unterstützt werden, die das übergeordnete Element ersetzen können, ohne das Programm anderweitig zu beschädigen. Diese Eigenschaft wird als Liskov-Substitution bezeichnet.Noch besser ist es jedoch, Ihre Abhängigkeiten umzukehren und überhaupt nicht nach bestimmten Typen zu suchen.
Fazit
Da wir das Ersetzen von Unterklassen unterstützen möchten, möchten wir in den meisten Fällen die Typprüfung mit vermeiden
type
und die Typprüfung mit bevorzugenisinstance
- es sei denn, Sie müssen die genaue Klasse einer Instanz wirklich kennen.quelle
isinstance(instance, y)
und verwendenfrom v.w.x import y
, und diese Prüfung importieren, aber wenn Sie sie instanziiereninstance
,from x import y
anstatt wie y in Ihre_Module.py importiert wurde, schlägt die Prüfung der Instanz fehl, obwohl es sich um dieselbe Klasse handelt.Letzteres wird bevorzugt, da Unterklassen ordnungsgemäß behandelt werden. In der Tat kann Ihr Beispiel noch einfacher geschrieben werden, da
isinstance()
der zweite Parameter ein Tupel sein kann:oder mit der
basestring
abstrakten Klasse:quelle
Laut Python-Dokumentation ist hier eine Aussage:
Sollte
isinstance()
also vorgezogen werdentype()
.quelle
Ein praktischer Unterschied in der Verwendung besteht darin, wie sie behandelt werden
booleans
:True
undFalse
sind nur Schlüsselwörter, die bedeuten1
und0
in Python. Somit,und
beide kehren zurück
True
. Beide Booleschen Werte sind eine Instanz einer Ganzzahl.type()
ist jedoch klüger:kehrt zurück
False
.quelle
Für die wirklichen Unterschiede können wir es in finden
code
, aber ich kann das Gerät des Standardverhaltens des nicht findenisinstance()
.Wir können jedoch den ähnlichen abc .__ instancecheck__ gemäß __instancecheck__ erhalten .
Von oben
abc.__instancecheck__
nach dem Test unten:Ich bekomme diese Schlussfolgerung, Für
type
:Für
isinstance
:Übrigens: Besser nicht mischen
relative and absolutely import
, verwendenabsolutely import
von project_dir (hinzugefügt vonsys.path
)quelle