1565 Stimmen

Was sind die Unterschiede zwischen type() und isinstance()?

Was sind die Unterschiede zwischen diesen beiden Codefragmenten?

Verwendung von type() :

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

Verwendung von isinstance() :

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

6 Stimmen

Hinweis:Wenn es sich nicht um str y unicode (wo Sie einfach überprüfen können basestring ), können Sie ein Tupel für die Prüfung auf mehrere Typen verwenden. Um zu prüfen, ob something es int o str verwenden. isinstance(something, (int, str)) .

2 Stimmen

type() gibt den Typ des Objekts zurück, das Sie als Argument angegeben haben, und ist normalerweise nicht nützlich, es sei denn, es wird mit einem realen Typ verglichen (wie type(9) == int ). isinstance() gibt einen booleschen Wert - true oder false - zurück, je nachdem, ob das Objekt vom angegebenen Typ ist. isinstance ist in den meisten Fällen eleganter zu verwenden als eine umständliche Gleichheitsprüfung zu schreiben.

1538voto

Alex Martelli Punkte 805329

Um den Inhalt der anderen (bereits guten!) Antworten zusammenzufassen, isinstance sorgt für Vererbung (eine Instanz einer abgeleiteten Klasse ist ein Instanz einer Basisklasse), während die Prüfung auf Gleichheit von type nicht (es verlangt Identität der Typen und lehnt Instanzen von Untertypen, auch bekannt als Unterklassen, ab).

Normalerweise wollen Sie in Python, dass Ihr Code die Vererbung unterstützt (da Vererbung so praktisch ist, wäre es schlecht, den Code, der Ihren Code verwendet, daran zu hindern, sie zu nutzen), also isinstance ist weniger schlimm als die Überprüfung der Identität von type s, weil es die Vererbung nahtlos unterstützt.

Es ist nicht so, dass isinstance es gut wohlgemerkt - es ist nur weniger schlecht als die Überprüfung der Gleichheit von Typen. Die normale, von Pythonic bevorzugte Lösung ist fast immer "Duck Typing": Versuchen Sie, das Argument als ob es war von einem bestimmten gewünschten Typ, machen Sie es in einem try / except Anweisung, die alle Ausnahmen abfängt, die auftreten könnten, wenn das Argument nicht tatsächlich von diesem Typ ist (oder von einem anderen Typ, der es gut nachahmt;-), und in der except Klausel, versuchen Sie etwas anderes (mit dem Argument "als ob" es von einem anderen Typ wäre).

basestring es ist jedoch ein ganz besonderer Fall - ein eingebauter Typ, der existiert nur um Ihnen die Verwendung von isinstance (beide str y unicode Unterklasse basestring ). Strings sind Sequenzen (man kann über sie schleifen, sie indizieren, sie zerschneiden, ...), aber im Allgemeinen möchte man sie als "skalare" Typen behandeln - es ist etwas unpraktisch (aber ein recht häufiger Anwendungsfall), alle Arten von Strings (und vielleicht andere skalare Typen, d.h. solche, über die man keine Schleife ziehen kann) auf die eine Art zu behandeln, alle Container (Listen, Sets, Dicts, ...) auf eine andere Art, und basestring plus isinstance hilft Ihnen dabei - die Gesamtstruktur dieser Redewendung ist etwa so:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

Man könnte sagen, dass basestring es un Abstrakte Basisklasse ("ABC") - es bietet keine konkrete Funktionalität für Unterklassen, sondern dient eher als "Marker", hauptsächlich zur Verwendung mit isinstance . Das Konzept ist offensichtlich ein wachsendes Konzept in Python, da PEP 3119 , die eine Verallgemeinerung davon einführt, wurde akzeptiert und ab Python 2.6 und 3.0 implementiert.

Der PEP stellt klar, dass ABCs zwar oft die Entenschreibung ersetzen können, aber im Allgemeinen kein großer Druck besteht, dies zu tun (siehe aquí ). ABCs, wie sie in neueren Python-Versionen implementiert sind, bieten jedoch zusätzliche Vorteile: isinstance (und issubclass ) kann jetzt mehr bedeuten als nur "[eine Instanz von] einer abgeleiteten Klasse" (insbesondere kann jede Klasse mit einem ABC "registriert" werden, so dass sie als Unterklasse und ihre Instanzen als Instanzen des ABCs angezeigt werden); und ABCs können auch zusätzlichen Komfort für tatsächliche Unterklassen auf sehr natürliche Weise über Template Method Design Pattern-Anwendungen bieten (siehe aquí y aquí [Teil II]] für weitere Informationen zum TM DP im Allgemeinen und speziell in Python, unabhängig von ABCs).

Für die zugrunde liegende Mechanik der ABC-Unterstützung, wie sie in Python 2.6 angeboten wird, siehe aquí ; für ihre 3.1-Version, die sehr ähnlich ist, siehe aquí . In beiden Versionen wird das Modul der Standardbibliothek Sammlungen (das ist die 3.1-Version - für die sehr ähnliche 2.6-Version siehe aquí ) bietet mehrere nützliche ABCs.

Für die Zwecke dieser Antwort ist das Wichtigste an ABCs (abgesehen von der wohl natürlicheren Platzierung der TM-DP-Funktionalität im Vergleich zur klassischen Python-Alternative der Mixin-Klassen wie UserDict.DictMixin ) ist, dass sie isinstance (und issubclass ) viel attraktiver und allgegenwärtiger (in Python 2.6 und in Zukunft) als sie es früher waren (in 2.5 und davor), und machen daher im Gegensatz dazu die Überprüfung der Typengleichheit zu einer noch schlechteren Praxis in neueren Python-Versionen, als sie es ohnehin schon war.

36 Stimmen

Es ist nicht so, dass isinstance gut ist, wohlgemerkt - es ist nur weniger schlecht als die Überprüfung der Gleichheit von Typen. Die normale, pythonische, bevorzugte Lösung ist fast immer "duck typing"' Dies ist eine ziemlich eingeschränkte Sichtweise: es gibt sehr gute Fälle für die Verwendung von isinstance(), z. B. in einem Interpreter, in dem die Typen die Grammatik widerspiegeln. Pythonisch" zu sein ist nicht alles!

6 Stimmen

Basestring ist in Python 3 nicht verfügbar.

1 Stimmen

@GeneCallahan, dass es sehr gute Fälle gibt, bedeutet nicht, dass das, was gesagt wurde, nicht eine gute allgemeine Regel ist. Ich stimme zu, dass eine vorherige Typenprüfung durchaus ihre Berechtigung hat, aber die Enten quaken zu lassen, sollte reichen. Die meisten Fälle flexibler und effizienter zu bearbeiten.

449voto

Peter Punkte 120325

Hier ist ein Beispiel, bei dem isinstance etwas erreicht, das type nicht:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

in diesem Fall ist ein Lkw-Objekt ein Fahrzeug, aber Sie werden dies erhalten:

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.

Mit anderen Worten, isinstance gilt auch für Unterklassen.

Siehe auch: Wie vergleicht man den Typ eines Objekts in Python?

172 Stimmen

Da es Fälle gibt, in denen Sie das isInstance-Verhalten nicht wünschen, würde ich behaupten, dass es kein "besser" gibt. Sie machen einfach etwas anderes.

33 Stimmen

-1, denn "isinstance ist besser als type" ist ein irreführender Kommentar. er wird wie " type ist veraltet, verwenden Sie isinstance Stattdessen" auf den ersten Blick. Was ich wollte, war zum Beispiel genau type() zu überprüfen, aber ich wurde aus diesem Grund für kurze Zeit in die Irre geführt (und musste ein wenig debuggen).

11 Stimmen

Das ist ein gutes Beispiel dafür, wie unterschiedlich sie arbeiten, aber ich hatte gerade einen Fall, in dem ich speziell eine type() und nicht isinstance() . Das eine ist nicht besser; sie sind für unterschiedliche Dinge gedacht.

134voto

Unterschiede zwischen isinstance() y type() in Python?

Typprüfung mit

isinstance(obj, Base)

lässt Instanzen von Unterklassen und mehrere mögliche Basen zu:

isinstance(obj, (Base1, Base2))

während die Typüberprüfung mit

type(obj) is Base

unterstützt nur den referenzierten Typ.


Nebenbei bemerkt, is ist wahrscheinlich besser geeignet als

type(obj) == Base

weil Klassen Singletons sind.

Typüberprüfung vermeiden - Polymorphismus verwenden (Duck-Typing)

In Python möchte man in der Regel jeden Typ für seine Argumente zulassen, ihn wie erwartet behandeln, und wenn sich das Objekt nicht wie erwartet verhält, wird ein entsprechender Fehler ausgegeben. Dies ist bekannt als Polymorphismus, auch bekannt als Duck-Typing.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

Wenn der obige Code funktioniert, können wir davon ausgehen, dass unser Argument eine Ente ist. So können wir in andere Dinge übergeben sind tatsächliche Untertypen von Ente:

function_of_duck(mallard)

oder die wie eine Ente funktionieren:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

und unser Code funktioniert immer noch.

Es gibt jedoch einige Fälle, in denen es wünschenswert ist, eine explizite Typüberprüfung durchzuführen. Vielleicht haben Sie sinnvolle Dinge mit verschiedenen Objekttypen zu tun. Zum Beispiel kann das Pandas Dataframe Objekt aus Dicts konstruiert werden o Aufzeichnungen. In einem solchen Fall muss Ihr Code wissen, um welche Art von Argument es sich handelt, damit er es richtig behandeln kann.

Also, um die Frage zu beantworten:

Unterschiede zwischen isinstance() y type() in Python?

Erlauben Sie mir, den Unterschied zu verdeutlichen:

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 wie folgt auf den Typ prüfen:

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')

Wenn wir versuchen, ein dict zu übergeben, das eine Unterklasse von dict (und das sollten wir auch können, wenn wir erwarten, dass unser Code dem Prinzip der Liskov-Ersatz , dass Subtypen durch Typen ersetzt werden können) bricht unser Code!

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

löst einen Fehler aus!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

Aber wenn wir die isinstance können wir die Liskov-Substitution unterstützen:

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')]))

gibt zurück. OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

Abstrakte Basisklassen

Wir können es sogar noch besser machen. collections bietet abstrakte Basisklassen, die Minimalprotokolle für verschiedene Typen erzwingen. In unserem Fall, wenn wir nur die Mapping Protokolls können wir Folgendes tun, wodurch unser Code noch flexibler wird:

from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

Antwort auf den Kommentar:

Es sollte beachtet werden, dass type verwendet werden kann, um gegen mehrere Klassen zu prüfen, indem type(obj) in (A, B, C)

Ja, Sie können auf die Gleichheit der Typen testen, aber verwenden Sie stattdessen die mehrfachen Grundlagen für den Kontrollfluss, es sei denn, Sie lassen ausdrücklich nur diese Typen zu:

isinstance(obj, (A, B, C))

Der Unterschied ist wiederum, dass isinstance unterstützt Unterklassen, die anstelle der übergeordneten Klasse verwendet werden können, ohne das Programm zu zerstören, eine Eigenschaft, die als Liskov-Substitution bekannt ist.

Noch besser ist es, wenn Sie Ihre Abhängigkeiten umkehren und überhaupt nicht nach bestimmten Typen suchen.

Schlussfolgerung

Da wir also das Ersetzen von Unterklassen unterstützen wollen, wollen wir in den meisten Fällen die Typüberprüfung mit type und bevorzugen die Typprüfung mit isinstance - es sei denn, Sie müssen wirklich die genaue Klasse einer Instanz kennen.

0 Stimmen

Wenn Sie your_module.py haben, wo Sie nach isinstance(instance, y) und verwenden from v.w.x import y und Sie importieren diese Prüfung, aber wenn Sie die instance Sie verwenden from x import y anstatt wie y in your_module.py importiert wurde, schlägt die isinstance-Prüfung fehl, obwohl es sich um dieselbe Klasse handelt.

70voto

John Millikin Punkte 190278

Letzteres ist zu bevorzugen, da es die Unterklassen richtig behandelt. Ihr Beispiel kann sogar noch einfacher geschrieben werden, weil isinstance() kann der zweite Parameter ein Tupel sein:

if isinstance(b, (str, unicode)):
    do_something_else()

oder unter Verwendung der basestring abstrakte Klasse:

if isinstance(b, basestring):
    do_something_else()

25voto

Alec Punkte 7040

Ein praktischer Unterschied bei der Verwendung besteht darin, wie sie mit booleans :

True y False sind nur Schlüsselwörter, die bedeuten 1 y 0 in Python. So,

isinstance(True, int)

et

isinstance(False, int)

beide kehren zurück True . Beide Booleschen sind eine Instanz einer ganzen Zahl. type() ist jedoch cleverer:

type(True) == int

gibt zurück. False .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X