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.
6 Stimmen
Hinweis:Wenn es sich nicht um
str
yunicode
(wo Sie einfach überprüfen könnenbasestring
), können Sie ein Tupel für die Prüfung auf mehrere Typen verwenden. Um zu prüfen, obsomething
esint
ostr
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 (wietype(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.