webentwicklung-frage-antwort-db.com.de

Wie kann man kanonisch nach Python suchen?

Wie lässt sich am besten prüfen, ob ein Objekt einen bestimmten Typ hat? Wie wäre es mit der Überprüfung, ob das Objekt von einem bestimmten Typ erbt?

Nehmen wir an, ich habe ein Objekt o. Wie überprüfe ich, ob es sich um eine str handelt?

1018
Herge

Um zu überprüfen, ob o eine Instanz von str oder einer Unterklasse von str ist, verwenden Sie isinstance (dies wäre die "kanonische" Methode):

if isinstance(o, str):

So prüfen Sie, ob der Typ von o genau str ist (Unterklassen ausschließen):

if type(o) is str:

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

if issubclass(type(o), str):

Weitere Informationen finden Sie unter Integrierte Funktionen in der Python Library-Referenz.

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

if isinstance(o, basestring):

da dies auch Unicode-Zeichenfolgen abfängt ( unicode ist keine Unterklasse von str; beide str und unicode sind Unterklassen von basestring ). Beachten Sie, dass basestring nicht mehr in Python 3 vorhanden ist, wo eine strikte Trennung von Zeichenfolgen ( str ) und Binärdaten ( bytes ) besteht.

Alternativ akzeptiert isinstance ein Tuple von Klassen. Dies gibt True zurück, wenn x eine Instanz einer Unterklasse von (str, Unicode) ist:

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

Der most Pythonic-Weg, um den Typ eines Objekts zu prüfen, besteht darin, ihn nicht zu prüfen.

Da Python Duck Typing anregt, sollten Sie nur try...except verwenden, um die Objektmethoden so zu verwenden, wie Sie sie verwenden möchten. Wenn Ihre Funktion nach einem beschreibbaren Dateiobjekt sucht, prüfen Sie mit nicht, ob es sich um eine Unterklasse von file handelt. Versuchen Sie einfach, die .write()-Methode zu verwenden!

Natürlich brechen diese schönen Abstraktionen manchmal zusammen und isinstance(obj, cls) ist das, was Sie brauchen. Aber sparsam verwenden.

163
Dan Lenski

isinstance(o, str) gibt true zurück, wenn o eine str ist oder von einem Typ ist, der von str erbt.

type(o) is str gibt true zurück, wenn und nur wenn o ein str ist. Es wird false zurückgegeben, wenn o von einem Typ ist, der von str erbt.

44
Herge

Nachdem die Frage gestellt und beantwortet wurde, Typhinweise wurden zu Python hinzugefügt . Tipptipps in Python ermöglichen das Prüfen von Typen, unterscheiden sich jedoch stark von statisch typisierten Sprachen. Tipptipps in Python ordnen den erwarteten Argumenttypen Funktionen zu Als zur Laufzeit zugreifbare Daten, die mit Funktionen verknüpft sind, und diese ermöglichen, dass Typen überprüft werden.

def foo(i: int):
    return i

foo(5)
foo('oops')

In diesem Fall soll ein Fehler für foo('oops') ausgelöst werden, da der mit Anmerkungen versehene Typ des Arguments int ist. Der hinzugefügte Typhinweis verursacht keinen Fehler , wenn das Skript normal ausgeführt wird. Es werden jedoch der Funktion Attribute hinzugefügt, die die erwarteten Typen beschreiben, die andere Programme abfragen und verwenden können, um nach Typfehlern zu suchen.

Eines dieser anderen Programme, mit denen der Typfehler ermittelt 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 "Offizialität" zu haben.)

Diese Art der Typprüfung unterscheidet sich von der Typprüfung in statisch 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 nötig sein und unnötige Fehler verursachen (z. B. muss das Argument wirklich genau vom Typ list sein oder ist etwas Iterierbares ausreichend?).

Der Vorteil der expliziten Typprüfung besteht darin, dass Fehler früher abgefangen und klarere Fehlermeldungen ausgegeben werden können als bei der Eingabe von Enten. Die genauen Anforderungen eines Ententyps können nur durch externe Dokumentation ausgedrückt werden (hoffentlich gründlich und genau), und Fehler bei inkompatiblen Typen können weit entfernt von ihrem Ursprung auftreten.

Die Typhinweise von Python sollen einen Kompromiss darstellen, bei dem Typen angegeben und überprüft werden können. Bei der normalen Codeausführung fallen jedoch keine zusätzlichen Kosten an.

Das Paket typing bietet Typvariablen, die in Typhinweisen verwendet werden können, um die erforderlichen Verhaltensweisen auszudrücken, ohne dass bestimmte Typen erforderlich sind. Beispielsweise enthält es Variablen wie Iterable und Callable, um Hinweise zu geben, ob ein Typ mit diesem Verhalten erforderlich ist.

Während Tippfehler die pythonischste Art sind, Typen zu überprüfen, ist es oft noch pythonischer, Typen überhaupt nicht zu überprüfen und sich auf das Eingeben von Enten zu verlassen. Tipptipps sind relativ neu und die Jury ist immer noch unschlüssig, wann sie die pythonischste Lösung sind. Ein relativ unumstrittener, aber sehr allgemeiner Vergleich: Typhinweise bieten eine Form der Dokumentation, die erzwungen werden kann, die es dem Code ermöglicht, früher Fehler zu generieren und leichter zu verstehen, Fehler abfangen kann, die bei der Eingabe von Enten nicht möglich sind, und die statisch überprüft werden kann (ungewöhnlich) Sinn, aber es ist immer noch außerhalb der Laufzeit). Auf der anderen Seite war Entenschreiben lange Zeit die pythonische Methode, erlegt dem statischen Schreiben keinen kognitiven Aufwand auf, ist weniger ausführlich und akzeptiert alle realisierbaren Typen und noch einige mehr.

23
Praxeolitic

Hier ist ein Beispiel, warum Entenschreiben böse ist, ohne zu wissen, wann es gefährlich ist. Zum Beispiel: Hier ist der Python-Code (der möglicherweise das korrekte Einrücken weglässt) Funktionen, um sicherzustellen, dass Sie, wenn Sie wirklich eine Ente brauchen, keine Bombe bekommen.

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()
17
Dmitry
isinstance(o, str)

Link zu Dokumenten

12

Ich denke, das Coole an der Verwendung einer dynamischen Sprache wie Python ist, dass Sie so etwas nicht wirklich prüfen sollten.

Ich würde einfach die erforderlichen Methoden für Ihr Objekt aufrufen und eine AttributeError abfangen. Später können Sie damit Ihre Methoden mit anderen (scheinbar nicht zusammenhängenden) Objekten aufrufen, um verschiedene Aufgaben auszuführen, z. B. das Verspotten eines Objekts zum Testen.

Ich habe dies häufig verwendet, um Daten aus dem Internet mit urllib2.urlopen() zu holen, die ein file wie object zurückgibt. Dies kann wiederum an fast jede Methode übergeben werden, die aus einer Datei liest, da sie dieselbe read()-Methode als echte Datei implementiert.

Ich bin mir jedoch sicher, dass es eine Zeit und einen Ort gibt, an dem isinstance() verwendet werden kann, sonst wäre es wahrscheinlich nicht da :)

6
Will Harding

Zu Hugo:

Sie meinen wahrscheinlich list und nicht array, aber das weist auf das gesamte Problem mit der Typprüfung hin. Sie möchten nicht wissen, ob das fragliche Objekt eine Liste ist. Sie möchten wissen, ob es sich um eine Art Sequenz oder um eine einzelne handelt Objekt. Versuchen Sie es also wie eine Sequenz zu verwenden.

Angenommen, Sie möchten das Objekt zu einer vorhandenen Sequenz hinzufügen, oder wenn es sich um eine Folge 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 Strings und/oder Sequenzen von Strings arbeiten - das ist knifflig, da ein String oft als einzelnes Objekt betrachtet wird, aber auch als Folge von Zeichen. Schlimmer als das, denn es ist wirklich eine Folge von Saiten mit einer einzigen Länge.

Normalerweise entscheide ich mich dafür, meine API so zu gestalten, dass nur ein einzelner Wert oder eine Sequenz akzeptiert wird. Das macht die Sache einfacher. Es ist nicht schwer, Ihren Einzelwert mit einem [ ] zu versehen, wenn Sie ihn bei Bedarf übergeben.

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

4
Chris Barker

Sie können den Typ einer Variablen mit __eines Typs überprüfen.

Ex:

>>> a = [1,2,3,4]  
>>> b = 1  
>>> type(a).__name__
'list'
>>> type(a).__== 'list'
True
>>> type(b).__== 'list'
False
>>> type(b).__name__
'int'
0

Für komplexere Typvalidierungen mag ich typeguard s Ansatz der Validierung basierend auf Python-Typ-Hinweisanmerkungen:

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 Überprüfungen 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) 
0
Granitosaurus