Wie kann am besten überprüft werden, ob ein bestimmtes Objekt von einem bestimmten Typ ist? Wie wäre es zu überprüfen, ob das Objekt von einem bestimmten Typ erbt?
Nehmen wir an, ich habe ein Objekt o
. Wie überprüfe ich, ob es ein ist str
?
Wie kann am besten überprüft werden, ob ein bestimmtes Objekt von einem bestimmten Typ ist? Wie wäre es zu überprüfen, ob das Objekt von einem bestimmten Typ erbt?
Nehmen wir an, ich habe ein Objekt o
. Wie überprüfe ich, ob es ein ist str
?
Antworten:
Verwenden Sie isinstance , um zu überprüfen, ob o
es sich um eine Instanz str
oder eine Unterklasse von handelt (dies wäre der "kanonische" Weg):str
if isinstance(o, str):
So überprüfen Sie, ob der Typ o
genau ist str
(Unterklassen ausschließen):
if type(o) is str:
Folgendes funktioniert ebenfalls und kann in einigen Fällen nützlich sein:
if issubclass(type(o), str):
Relevante Informationen finden Sie unter Integrierte Funktionen in der Python-Bibliotheksreferenz.
Noch ein Hinweis: Wenn Sie in diesem Fall Python 2 verwenden, möchten Sie möglicherweise tatsächlich Folgendes verwenden:
if isinstance(o, basestring):
weil dies auch Unicode-Strings abfängt ( unicode
ist keine Unterklasse von str
; beide str
und unicode
sind Unterklassen von basestring
). Beachten Sie, dass basestring
es in Python 3 nicht mehr existiert, wo Strings ( ) und Binärdaten ( ) strikt getrennt werden .str
bytes
Akzeptiert alternativ isinstance
ein Tupel von Klassen. Dies wird zurückgegeben, True
wenn o
es sich um eine Instanz einer Unterklasse handelt von (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
dann ist es nicht auch wahr, dass isinstance(a, Object)
. Wenn aber type(a) is SubClassOfObject
dann type(a) is Object == False
doch isinstance(a, Object) == True
. Recht?
a is b
bedeutet, dass a und b genau dasselbe sind, dh Verweise auf dieselbe Entität im Speicher. Also a
und b
müsste genau die gleiche Klasse sein, keine Unterklassen wie bei isinstance()
. Siehe zum Beispiel stackoverflow.com/a/133024/1072212
Die meisten Pythonic Weg , um den Typ eines Objekts zu überprüfen , ist ... nicht zu überprüfen.
Da Python Duck Typing unterstützt , sollten Sie try...except
die Methoden des Objekts nur so verwenden, wie Sie sie verwenden möchten. Wenn Ihre Funktion also nach einem beschreibbaren Dateiobjekt sucht, überprüfen Sie nicht , ob es sich um eine Unterklasse file
handelt. Versuchen Sie einfach, die .write()
Methode zu verwenden!
Natürlich brechen diese schönen Abstraktionen manchmal zusammen und isinstance(obj, cls)
sind genau das, was Sie brauchen. Aber sparsam verwenden.
if hasattr(ob, "write") and callable(ob.write):
oder etwas func = getattr(ob, "write", None)
if callable(func): ...
hasattr
nur ein AttributeError unterdrückt - Siehe: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
wird zurückgegeben, True
wenn o
es sich um einen str
oder einen Typ handelt, von dem erbt str
.
type(o) is str
wird True
genau dann zurückkehren, wenn o
es sich um eine str handelt. Es wird zurückgegeben, False
wenn o
es sich um einen Typ handelt, der von erbt str
.
isinstance
und type(var) == type('')
nicht klar ist.
Nachdem die Frage gestellt und beantwortet wurde, wurden Python Tipphinweise hinzugefügt . Typhinweise in Python ermöglichen die Überprüfung von Typen, jedoch auf eine ganz andere Weise als bei statisch typisierten Sprachen. Typhinweise in Python verknüpfen die erwarteten Argumenttypen mit Funktionen als zur Laufzeit zugängliche Daten, die Funktionen zugeordnet sind, und ermöglichen die Überprüfung von Typen. Beispiel für die Syntax von Typhinweisen:
def foo(i: int):
return i
foo(5)
foo('oops')
In diesem Fall soll ein Fehler ausgelöst werden, foo('oops')
da der mit Anmerkungen versehene Typ des Arguments lautet int
. Der Mehr Typ Hinweis nicht dazu führen , ein Fehler auftreten , wenn das Skript normal ausgeführt wird. Der Funktion werden jedoch Attribute hinzugefügt, die die erwarteten Typen beschreiben, die andere Programme abfragen und zur Überprüfung auf Typfehler verwenden können.
Eines dieser anderen Programme, mit denen der Typfehler gefunden werden kann, ist mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Möglicherweise müssen Sie mypy
von Ihrem Paketmanager installieren . Ich glaube nicht, dass es mit CPython geliefert wird, aber es scheint ein gewisses Maß an "Offiziellität" zu haben.)
Die Typprüfung auf diese Weise unterscheidet sich von der Typprüfung in statisch typisierten kompilierten Sprachen. Da Typen in Python dynamisch sind, muss die Typprüfung zur Laufzeit durchgeführt werden, was selbst bei korrekten Programmen Kosten verursacht, wenn wir darauf bestehen, dass dies bei jeder Gelegenheit geschieht. Explizite Typprüfungen können auch restriktiver sein als erforderlich und unnötige Fehler verursachen (z. B. muss das Argument wirklich vom genauen list
Typ sein oder ist etwas iterierbares ausreichend?).
Der Vorteil der expliziten Typprüfung besteht darin, dass Fehler früher erkannt und klarere Fehlermeldungen ausgegeben werden können als beim Entenschreiben. Die genauen Anforderungen eines Ententyps können nur mit externer Dokumentation ausgedrückt werden (hoffentlich gründlich und genau), und Fehler von inkompatiblen Typen können weit entfernt von ihrem Ursprung auftreten.
Die Typhinweise von Python sollen einen Kompromiss bieten, bei dem Typen angegeben und überprüft werden können, während der normalen Codeausführung jedoch keine zusätzlichen Kosten entstehen.
Das typing
Paket bietet Typvariablen, die in Typhinweisen verwendet werden können, um das erforderliche Verhalten auszudrücken, ohne dass bestimmte Typen erforderlich sind. Beispielsweise enthält es Variablen wie Iterable
und Callable
für Hinweise, um die Notwendigkeit eines beliebigen Typs mit diesen Verhaltensweisen anzugeben.
Während Typhinweise die pythonischste Methode sind, um Typen zu überprüfen, ist es oft noch pythonischer, Typen überhaupt nicht zu überprüfen und sich auf die Eingabe von Enten zu verlassen. Tipphinweise sind relativ neu und die Jury ist sich noch nicht sicher, wann sie die pythonischste Lösung sind. Ein relativ unumstrittener, aber sehr allgemeiner Vergleich: Typhinweise bieten eine Form der Dokumentation, die erzwungen werden kann, es Code ermöglicht, frühere und leichter verständliche Fehler zu generieren, Fehler abfangen kann, die bei der Eingabe von Enten nicht möglich sind, und statisch überprüft werden kann (in ungewöhnlichen Fällen) Sinn, aber es ist immer noch außerhalb der Laufzeit). Auf der anderen Seite war das Tippen von Enten lange Zeit der pythonische Weg, erlegt nicht den kognitiven Aufwand für statisches Tippen auf, ist weniger ausführlich und akzeptiert alle brauchbaren Typen und noch einige mehr.
mypy
sind ein Python-Modul, mit importlib
dem auf diese Daten zugegriffen wird . Ob dies eine "statische Typprüfung" ist, ist eine philosophische Frage, unterscheidet sich jedoch von den meisten Erwartungen, da der normale Sprachinterpreter und die Importmaschinerie beteiligt sind.
Hier ist ein Beispiel, warum das Tippen von Enten böse ist, ohne zu wissen, wann es gefährlich ist. Zum Beispiel: Hier ist der Python-Code (möglicherweise ohne richtiges Einrücken). Beachten Sie, dass diese Situation vermieden werden kann, indem Sie sich um die Instanz und die Unterklasse der Funktionen kümmern, um sicherzustellen, dass Sie keine Bombe bekommen, wenn Sie wirklich eine Ente brauchen.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
talk erstellen und überschreiben (). Oder eher class ChineseCancerDuck(Duck)
mit einer bösen Nebenwirkung, die erst Jahre später auftritt. Sie sollten Ihr Kind besser beaufsichtigen (und ihr Spielzeug gründlich testen :)
__file__
Attribut (das häufig zur Identifizierung dateiähnlicher Objekte verwendet wird) überschreiben , um etwas anderes zu bedeuten.
isinstance(o, str)
Ich denke, das Coole an einer dynamischen Sprache wie Python ist, dass man so etwas wirklich nicht überprüfen muss.
Ich würde einfach die erforderlichen Methoden für Ihr Objekt aufrufen und eine abfangen AttributeError
. Später können Sie Ihre Methoden mit anderen (scheinbar nicht verwandten) Objekten aufrufen, um andere Aufgaben auszuführen, z. B. das Verspotten eines Objekts zum Testen.
Ich habe dies oft verwendet, um Daten aus dem Web zu holen, mit urllib2.urlopen()
denen ein dateiähnliches Objekt zurückgegeben wird. Dies kann wiederum an fast jede Methode übergeben werden, die aus einer Datei liest, da dieselbe read()
Methode wie eine echte Datei implementiert wird .
Aber ich bin mir sicher, dass es eine Zeit und einen Ort für die Nutzung gibt isinstance()
, sonst wäre es wahrscheinlich nicht da :)
Für komplexere Typüberprüfungen gefällt mir der Ansatz von typeguard , anhand von Anmerkungen zu Python-Typ-Hinweisen zu validieren:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Sie können sehr komplexe Validierungen auf sehr saubere und lesbare Weise durchführen.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Sie können den Typ einer Variablen mit __name__ eines Typs überprüfen.
Ex:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Zu Hugo:
Du meinst wahrscheinlich list
eher alsarray
, aber das weist auf das gesamte Problem bei der Typprüfung hin - Sie möchten nicht wissen, ob es sich bei dem fraglichen Objekt um eine Liste handelt, Sie möchten wissen, ob es sich um eine Sequenz handelt oder ob es sich um ein einzelnes Objekt handelt. Versuchen Sie also, es wie eine Sequenz zu verwenden.
Angenommen, Sie möchten das Objekt einer vorhandenen Sequenz hinzufügen, oder wenn es sich um eine Sequenz von Objekten handelt, fügen Sie alle hinzu
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Ein Trick dabei ist, wenn Sie mit Zeichenfolgen und / oder Zeichenfolgenfolgen arbeiten - das ist schwierig, da eine Zeichenfolge oft als einzelnes Objekt betrachtet wird, aber auch als Zeichenfolge. Schlimmer noch, da es sich wirklich um eine Folge von Strings mit einfacher Länge handelt.
Normalerweise entwerfe ich meine API so, dass sie nur einen einzelnen Wert oder eine Sequenz akzeptiert - das erleichtert die Arbeit. Es ist nicht schwer, einen [ ]
Wert um Ihren einzelnen Wert zu setzen, wenn Sie ihn bei Bedarf übergeben.
(Dies kann jedoch zu Fehlern bei Zeichenfolgen führen, da diese wie Sequenzen aussehen.)
Eine einfache Möglichkeit, den Typ zu überprüfen, besteht darin, ihn mit etwas zu vergleichen, dessen Typ Sie kennen.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Ich denke, der beste Weg ist, Ihre Variablen gut einzugeben. Sie können dies tun, indem Sie die Bibliothek "Typing" verwenden.
Beispiel:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Sie können mit der folgenden Zeile überprüfen, welcher Zeichentyp der angegebene Wert ist:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)