Unterschiede zwischen isinstance()
und type()
in Python?
Typprüfung mit
isinstance(obj, Base)
ermöglicht Instanzen von Unterklassen und mehrere mögliche Basen:
isinstance(obj, (Base1, Base2))
wohingegen Typprüfung mit
type(obj) is Base
unterstützt nur den Typ, auf den verwiesen wird.
Als Nebenbemerkung is
ist wahrscheinlich angemessener als
type(obj) == Base
weil 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.
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 anderen Dingen tatsächliche Untertypen von Enten übergeben:
function_of_duck(mallard)
oder das funktioniert wie eine Ente:
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 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()
und type()
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:
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 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!:
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 verwenden isinstance
, können wir 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')]))
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 das Mapping
Protokoll erwarten , können wir Folgendes tun, und unser Code wird noch flexibler:
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 Kommentar:
Es sollte beachtet werden, dass der Typ verwendet werden kann, um mit mehreren Klassen zu vergleichen type(obj) in (A, B, C)
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:
isinstance(obj, (A, B, C))
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 bevorzugen isinstance
- es sei denn, Sie müssen die genaue Klasse einer Instanz wirklich kennen.
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))
.