Frage Was ist die kanonische Methode, um in Python nach Typ zu suchen?


Was ist der beste Weg zu überprüfen, ob ein bestimmtes Objekt einen bestimmten Typ hat? Wie wäre es mit der Überprüfung, ob das Objekt von einem bestimmten Typ erbt?

Sagen wir, ich habe ein Objekt o. Wie überprüfe ich, ob es ein str?


886
2017-09-30 11:00


Ursprung


Antworten:


Um zu überprüfen, ob o ist eine Instanz von str oder irgendeine Unterklasse von str, benutzen isinstanz (Dies wäre der "kanonische" Weg):

if isinstance(o, str):

Um zu überprüfen, ob der Typ von o ist genau str:

if type(o) is str:

Folgendes funktioniert auch und kann in einigen Fällen nützlich sein:

if issubclass(type(o), str):

if type(o) in ([str] + str.__subclasses__()):

Sehen Eingebaute Funktionen in der Python-Bibliothek Referenz für relevante Informationen.

Noch eine Anmerkung: Wenn Sie in diesem Fall Python 2 verwenden, möchten Sie möglicherweise Folgendes verwenden:

if isinstance(o, basestring):

weil das auch Unicode-Zeichenfolgen abfangen wird (unicode ist keine Unterklasse von str; beide str und unicode sind Unterklassen von basestring). Beachten Sie, dass basestring existiert nicht mehr in Python 3, wo es ist eine strikte Trennung von Saiten (str) und binäre Daten (bytes).

Alternative, isinstance akzeptiert ein Tupel von Klassen. Dies wird True zurückgeben, wenn x eine Instanz einer beliebigen Unterklasse von (str, unicode) ist:

if isinstance(o, (str, unicode)):

1104
2017-09-30 11:07



Das die meisten Pythonischer Weg, um den Typ eines Objekts zu überprüfen, ist ... es nicht zu überprüfen.

Seit Python ermutigt Ente tippen, sollten Sie nur versuchen, die Methoden des Objekts so zu verwenden, wie Sie sie verwenden möchten. Wenn Ihre Funktion nach einem beschreibbaren Dateiobjekt sucht, nicht überprüfen Sie, dass es eine Unterklasse von ist fileVersuche es einfach zu benutzen .write() Methode!

Natürlich brechen diese netten Abstraktionen manchmal zusammen und isinstance(obj, cls) ist was du brauchst. Aber sparsam.


142
2017-09-30 17:40



isinstance(o, str) wird zurückkehren true ob o ist ein str oder ist von einem Typ, von dem er erbt str.

type(o) is str wird zurückkehren true dann und nur dann, wenn o ist eine str. Es wird zurückkehren false ob o ist von einem Typ, von dem er erbt str. ----


38
2017-09-30 11:05



Nachdem die Frage gestellt und beantwortet wurde, Typhinweise wurden zu Python hinzugefügt. Typhinweise in Python ermöglichen die Überprüfung von Typen, jedoch auf eine ganz andere Art als bei statisch typisierten Sprachen. Type-Hinweise in Python verknüpfen die erwarteten Arten von Argumenten mit Funktionen als Runtime-zugängliche Daten, die mit Funktionen assoziiert sind, und dies erlaubt für zu prüfende Typen. Beispiel für eine Typhinweis-Syntax:

def foo(i: int):
    return i

foo(5)
foo('oops')

In diesem Fall wollen wir einen Fehler auslösen foo('oops') da der annotierte Typ des Arguments ist int. Der hinzugefügte Typhinweis nicht Ursache Ein Fehler tritt auf, wenn das Skript normal ausgeführt wird. Es fügt jedoch Attribute zu der Funktion hinzu, die die erwarteten Typen beschreibt, die andere Programme abfragen und verwenden können, um nach Typfehlern zu suchen.

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"

(Sie müssen möglicherweise installieren mypy von Ihrem Paketmanager. Ich denke nicht, dass es mit CPython kommt, aber scheint ein gewisses Maß an "Offizialität" zu haben.)

Die Typüberprüfung unterscheidet sich von der Typüberprü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 als erforderlich sein und unnötige Fehler verursachen (z. B. muss das Argument wirklich genau sein) list tippen oder ist alles iterierbar genug?).

Der Vorteil der expliziten Typprüfung besteht darin, dass sie früher Fehler erkennen und deutlichere Fehlermeldungen ausgeben kann als die Duck-Typisierung. Die genauen Anforderungen eines Ducktyps können nur mit einer externen Dokumentation ausgedrückt werden (hoffentlich ist sie gründlich und genau) und Fehler von inkompatiblen Typen können weit entfernt von ihrem Ursprung auftreten.

Pythons Type-Hinweise sollen einen Kompromiss darstellen, bei dem Typen spezifiziert und überprüft werden können, aber es gibt keine zusätzlichen Kosten während der üblichen Code-Ausführung.

Das typing Paket bietet Typvariablen, die in Typhinweisen verwendet werden können, um benötigtes Verhalten auszudrücken, ohne dass bestimmte Typen erforderlich sind. Zum Beispiel 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 pythischste Art sind, Typen zu überprüfen, ist es oft noch mehr Pythonic, überhaupt keine Typen zu überprüfen und sich auf die Eingabe von Enten zu verlassen. Typhinweise sind relativ neu und die Jury ist immer noch am Ende, wenn sie die pythonischste Lösung ist. Ein relativ unumstrittener, aber sehr allgemeiner Vergleich: Typhinweise bieten eine Form der Dokumentation, die durchgesetzt werden kann, Code ermöglicht, frühere und leichter zu verstehende Fehler zu erzeugen, Fehler zu erfassen, die bei der Tippeingabe nicht möglich sind, und statisch zu überprüfen (in einer ungewöhnlichen Sinn, aber es ist immer noch außerhalb der Laufzeit). Auf der anderen Seite ist die Enten-Typisierung für lange Zeit die pythonische Methode, sie stellt den kognitiven Aufwand der statischen Typisierung nicht auf, ist weniger ausführlich und akzeptiert alle lebensfähigen Typen und dann einige.


17
2018-05-06 16:12



Hier ist ein Beispiel, warum Ente tippen ist böse, ohne zu wissen, wann es gefährlich ist. Zum Beispiel: Hier ist der Python-Code (unter Umständen das richtige Einrücken auslassen), beachten Sie, dass dies Die Situation ist vermeidbar, indem man sich beispielsweise um Funktionen kümmert und sicherstellt, dass man, wenn man wirklich eine Ente braucht, keine Bombe bekommt.

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

12
2018-01-25 23:54



isinstance(o, str)

Link zu den Dokumenten


10
2017-09-30 11:01



Ich finde es cool, wenn man eine dynamische Sprache wie Python verwendet, sollte man wirklich nicht so etwas überprüfen müssen.

Ich würde einfach die benötigten Methoden auf deinem Objekt aufrufen und einen fangen AttributeError. Später können Sie dann Ihre Methoden mit anderen (scheinbar nicht zusammenhängenden) Objekten aufrufen, um verschiedene Aufgaben auszuführen, z. B. ein Objekt zum Testen zu verspotten.

Ich habe das oft benutzt, um Daten aus dem Internet zu erhalten urllib2.urlopen() was zurückgibt a Datei wie Objekt. Dies kann wiederum an fast jede Methode übergeben werden, die aus einer Datei liest, weil sie dieselbe implementiert read() Methode als echte Datei.

Aber ich bin mir sicher, dass es eine Zeit und einen Ort gibt, an dem man es benutzen kann isinstance()sonst wäre es wahrscheinlich nicht da :)


5
2017-09-30 13:33



Zu Hugo:

Du meinst es wahrscheinlich list eher, als array, aber das weist auf das ganze Problem mit der Typprüfung hin - Sie wollen nicht wissen, ob das fragliche Objekt eine Liste ist, ob Sie wissen wollen, ob es sich um eine Art Sequenz handelt oder ob es ein einzelnes Objekt ist. Also versuche es wie eine Sequenz zu benutzen.

Angenommen, Sie möchten das Objekt zu einer vorhandenen Sequenz hinzufügen oder wenn es sich um eine Sequenz von Objekten handelt, fügen Sie alle Objekte hinzu

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

Ein Trick dabei ist, wenn Sie mit Strings und / oder Sequenzen von Strings arbeiten - das ist knifflig, da ein String oft als einzelnes Objekt betrachtet wird, aber auch eine Folge von Zeichen. Schlimmer als das, da es sich wirklich um eine Folge von Einzellängen handelt.

Normalerweise entscheide ich mich dafür, meine API so zu gestalten, dass sie nur einen einzelnen Wert oder eine Sequenz akzeptiert - das macht die Dinge einfacher. Es ist nicht schwer, ein zu setzen [ ] um Ihren einzelnen Wert, wenn Sie es bei Bedarf übergeben.

(Dies kann jedoch zu Fehlern bei Strings führen, da sie wie Sequenzen aussehen.)


2
2017-08-01 16:07