Was ist der kanonische Weg, um in Python nach Typ zu suchen?

Lesezeit: 12 Minuten

Benutzer-Avatar
Herge

Wie überprüfe ich, ob ein Objekt von einem bestimmten Typ ist oder ob es von einem bestimmten Typ erbt?

Wie überprüfe ich, ob das Objekt o ist vom Typ str?

  • Ich denke, Mr. Coombs übersieht Beispiele wie nicht-JSON-serialisierbare Klassen. Wenn Sie einen großen Datenblock durch eine Funktion leiten (deren Code Sie nicht beeinflussen können), möchten Sie möglicherweise bestimmte Teile dieser Daten beispielsweise in ein konvertieren, bevor Sie sie übergeben. So zumindest ich bin auf dieser Seite gelandet…

    – John Carell

    24. November 2015 um 18:45 Uhr


  • Es scheint, dass der häufigste Grund für diese Frage darin besteht, dass man zwischen Zeichenfolgen und iterierbaren Zeichenfolgen unterscheiden möchte. Das ist eine knifflige Frage, weil Strings sind Iterables von Strings — ein einzelner Zeichenstring ist sogar eine Folge von sich selbst (als ich das letzte Mal nachgesehen habe — man sollte sich wahrscheinlich nicht darauf verlassen). Aber würde irgendjemand jemals etwas Schnurartiges gebrauchen können? Ja. Die Antwort auf “Was soll ich tun, um zwischen Zeichenfolgen und anderen iterierbaren Zeichenfolgen zu unterscheiden?” ist richtig: “Es hängt davon ab, was Sie versuchen zu tun”. 😀

    – klack

    28. Juli 2016 um 12:22 Uhr


  • Anmerkungen vom Typ Python sind jetzt eine Sache. Schauen Sie sich an mypy

    – Sheena

    5. Oktober 2018 um 8:54 Uhr

Benutzer-Avatar
Fredrik Johansson

Verwenden isinstance um zu prüfen ob o ist eine Instanz von str oder eine Unterklasse von str:

if isinstance(o, str):

Um zu überprüfen, ob die Art von o ist genau str, ausgenommen Unterklassen von str:

if type(o) is str:

Noch eine Alternative zu oben:

if issubclass(type(o), str):

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


Suche nach Strings in Python 2

Für Python 2 ist dies eine bessere Möglichkeit, um zu überprüfen, ob o ist eine Zeichenfolge:

if isinstance(o, basestring):

da dies auch Unicode-Strings abfängt. unicode ist keine Unterklasse von str; wohingegen beide str und unicode sind Unterklassen von basestring. In Python3, basestring existiert nicht mehr, da es gibt eine strikte Trennung von Saiten (str) und Binärdaten (bytes).

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

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

  • str.__subclasses__() gibt nur die direkten Unterklassen von str zurück und macht nicht dasselbe wie issubclass() oder isinstance(). (Dazu müssten Sie rekursiv .__subclasses__() aufrufen.

    – Thomas Wouters

    30. September 2008 um 12:22 Uhr

  • Dies ist eine gute Antwort, aber ich denke, sie sollte wirklich mit einer Warnung beginnen, dass Sie dies normalerweise nicht in Python tun sollten. So wie es ist, scheint es die Annahme zu bestätigen, dass dies eine “kanonische Sache in Python” ist, was es nicht ist.

    – Jon Coombs

    11. Dezember 2014 um 20:54 Uhr

  • Was ist der Unterschied zwischen Instanz und “genau”? Wenn type(a) is Object dann ist es nicht auch so isinstance(a, Object). jedoch, wenn type(a) is SubClassOfObjectdann type(a) is Object == Falseaber isinstance(a, Object) == True. Recht?

    – mavavilj

    3. Mai 2017 um 13:49 Uhr

  • @mavavilj – a is b bedeutet, dass a und b genau dasselbe sind, dh Verweise auf dieselbe Entität im Speicher. So a und b müsste genau dieselbe Klasse sein, nicht Unterklassen, wie bei isinstance(). Siehe zum Beispiel stackoverflow.com/a/133024/1072212

    – Terry Braun

    9. Juni 2017 um 17:47 Uhr

  • @JonCoombs Nach der Begründung von PEP 622, isinstance() ist die am zweithäufigsten aufgerufene eingebaute Funktion, nach len(). Ich denke, das müssen wir akzeptieren isinstance ist de facto kanonisches Python.

    – BallpointBen

    4. Juli 2020 um 16:10 Uhr

Benutzer-Avatar
Dan Lenski

Das die meisten Der pythonische Weg, den Typ eines Objekts zu überprüfen, ist … es nicht zu überprüfen.

Da Python ermutigt Duck-Typisierungsollten Sie nur try...except um die Methoden des Objekts so zu verwenden, wie Sie sie verwenden möchten. Wenn Ihre Funktion also nach einem beschreibbaren Dateiobjekt sucht, nicht Überprüfen Sie, ob es sich um eine Unterklasse von handelt fileversuchen Sie einfach, es zu verwenden .write() Methode!

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

  • IMHO ist der pythonischste Weg, mit jedem Argument fertig zu werden, das gegeben wird. In meinem Code kann ich oft nicht wissen, ob ich ein Objekt oder ein Array von Objekten erhalte, und ich verwende intern eine Typprüfung, um ein einzelnes Objekt in eine Liste mit einem Element zu konvertieren.

    – sastanin

    12. Januar 2009 um 11:21 Uhr

  • Anstatt nur zu versuchen, seine Write-Methode zu verwenden, gibt es Zeiten, in denen Sie dies tun möchten, ohne eine Ausnahme zu verursachen. In diesem Fall könntest du… if hasattr(ob, "write") and callable(ob.write): Oder sparen Sie sich einen Diktatzugriff … func = getattr(ob, "write", None) if callable(func): ...

    – Ideengeber42

    25. August 2012 um 19:41 Uhr


  • Duck-Typing ist ungefähr verwenden eine Bibliothek. Bei der Typprüfung geht es um Schreiben eine Bibliothek. Nicht die gleiche Problemdomäne.

    – RickyA

    6. Dezember 2012 um 20:26 Uhr

  • @RickyA, ich bin anderer Meinung. Beim Ententippen geht es um die Interaktion mit Objekten über Schnittstellen mit bekannter Semantik. Dies kann entweder für Bibliothekscode gelten oder für den Code, der eine solche Bibliothek verwendet.

    – Dan Lenski

    16. Juni 2014 um 19:27 Uhr

  • @nyuszika7h, in Python3 hasattr unterdrückt nur einen AttributeError – Siehe: docs.python.org/3.4/library/functions.html#hasattr

    – Ideengeber42

    26. Dezember 2014 um 3:46 Uhr

Benutzer-Avatar
Herge

isinstance(o, str) wird zurückkehren True wenn o ist ein str oder ist von einem Typ, der von erbt str.

type(o) is str wird zurückkehren True dann und nur dann, wenn o ist eine Str. Es wird zurückkehren False wenn o ist von einem Typ, der von erbt str.

  • Dies schlägt natürlich fehl, wenn das Objekt keine Instanz von ‘str’ ist, sondern stattdessen etwas Stringähnliches. Wie Unicode, mmap, UserString oder andere benutzerdefinierte Typen. Der übliche Ansatz in Python besteht darin, keine Typprüfungen durchzuführen.

    – Thomas Wouters

    30. September 2008 um 11:07 Uhr

  • Das ist sehr hilfreich. Denn der Unterschied zw isinstance und type(var) == type('') ist nicht klar.

    – sastanin

    12. Januar 2009 um 11:18 Uhr

Benutzer-Avatar
Praxeolit

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 in statisch typisierten Sprachen. Typhinweise in Python ordnen die erwarteten Typen von Argumenten Funktionen als zur Laufzeit zugängliche Daten zu, die Funktionen zugeordnet sind, und dies erlaubt für zu prüfende Typen. Beispiel für Typhinweis-Syntax:

def foo(i: int):
    return i

foo(5)
foo('oops')

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

Eines dieser anderen Programme, mit denen Sie den Typfehler finden können, ist mypy:

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

(Möglicherweise müssen Sie installieren mypy von Ihrem Paketmanager. Ich glaube nicht, dass es mit CPython kommt, aber es scheint ein gewisses Maß an “Offizialitä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 mit Kosten verbunden ist – sogar für korrekte Programme – 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 sein list Typ oder ist etwas Iterierbares ausreichend?).

Der Vorteil der expliziten Typprüfung besteht darin, dass sie Fehler früher abfangen und klarere Fehlermeldungen ausgeben kann als Duck-Typing. Die genauen Anforderungen eines Ententyps können nur mit externer Dokumentation (hoffentlich gründlich und genau) ausgedrückt werden, 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, aber während der normalen Codeausführung keine zusätzlichen Kosten entstehen.

Das typing Das Paket bietet Typvariablen, die in Typhinweisen verwendet werden können, um erforderliche Verhaltensweisen auszudrücken, ohne dass bestimmte Typen erforderlich sind. Beispielsweise enthält es Variablen wie Iterable und Callable für Hinweise, um die Notwendigkeit für jeden Typ mit diesen Verhaltensweisen anzugeben.

Während Typhinweise die pythonischste Art sind, Typen zu überprüfen, ist es oft noch pythonischer, Typen überhaupt nicht zu überprüfen und sich auf Duck-Typing zu verlassen. Type Hints sind relativ neu und die Jury ist sich noch nicht einig, wann sie die pythonischste Lösung sind. Ein relativ unumstrittener, aber sehr allgemeiner Vergleich: Typhinweise bieten eine Form der Dokumentation, die erzwungen werden kann, Code früher und leichter verständliche Fehler generieren lässt, Fehler abfangen kann, die Duck-Typing nicht kann, und statisch überprüft werden kann (in einer ungewöhnlichen Sinn, aber es ist immer noch außerhalb der Laufzeit). Auf der anderen Seite war Ententypisierung lange Zeit der pythonische Weg, erlegt nicht den kognitiven Overhead des statischen Typisierens auf, ist weniger ausführlich und akzeptiert alle brauchbaren Typen und noch einige mehr.

Benutzer-Avatar
SuperNova

Im Python 3.10können Sie verwenden | in isinstance:

>>> isinstance('1223', int | str) 
True

>>> isinstance('abcd', int | str) 
True

  • Das ist cool und alles … aber ich sehe nicht wirklich, was das hier hinzufügt oder wie es wirklich hilfreich ist.

    – Einfach schöne Kunst

    18. Oktober 2021 um 1:45 Uhr

  • Eines der großartigen Dinge in Python ist, dass es vermeidet, zufällige Symbole im gesamten Code zu haben. Leider verschwindet diese Eigenschaft im Laufe der Zeit langsam.

    – Ein Karem

    24. Juni um 10:26 Uhr


Benutzer-Avatar
Yerramsetty Rohit

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'

  • Das ist cool und alles … aber ich sehe nicht wirklich, was das hier hinzufügt oder wie es wirklich hilfreich ist.

    – Einfach schöne Kunst

    18. Oktober 2021 um 1:45 Uhr

  • Eines der großartigen Dinge in Python ist, dass es vermeidet, zufällige Symbole im gesamten Code zu haben. Leider verschwindet diese Eigenschaft im Laufe der Zeit langsam.

    – Ein Karem

    24. Juni um 10:26 Uhr


Hier ist ein Beispiel, warum Ententippen böse ist, ohne zu wissen, wann es gefährlich ist.

Zum Beispiel: Hier ist der Python-Code (möglicherweise ohne richtige Einrückung), beachten Sie, dass diese Situation vermeidbar ist, indem Sie sich um die Funktionen isinstance und issubclassof kümmern, um sicherzustellen, dass Sie keine Bombe bekommen, wenn Sie wirklich eine Ente brauchen.

class Bomb:
    def talk(self):
        self.explode()

    def explode(self):
        print("BOOM!, The bomb explodes.")

class Duck:
    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 take_duck(self, duck):
        self.kids_duck = duck
        print("The kid accepts the duck, and happily skips along.")

    def do_your_thing(self):
        print("The kid tries to get the duck to talk.")
        self.kids_duck.talk()

my_kid = Kid()
my_kid.take_duck(Bomb())
my_kid.do_your_thing()

HINWEIS: Das Beispiel ist alt, naiv und die Gefahr wird stark übertrieben. Es bleibt als Proof of Concept ohne größere Änderungen außer dem Update auf Python 3. Ich erinnere mich nicht, was mich dazu veranlasst hat, dies ursprünglich zu schreiben.

  • Bomben sprechen nicht. Fügen Sie keine unsinnigen Methoden hinzu, und dies wird nicht passieren.

    Benutzer1804599

    18. März 2014 um 11:04 Uhr

  • @Dmitry, das ist die häufige Kritik an Duck Typing: en.wikipedia.org/wiki/Duck_typing#Criticism … Sie sagen im Grunde, dass jede Schnittstelle, deren Semantik nicht durch die Sprache erzwungen wird, böse ist. Ich glaube, das ist eher der Ansatz von Java. Der springende Punkt bei Pythons Duck-Typing ist, dass es nur funktioniert, wenn es eine allgemein aufrechterhaltene Konvention darüber gibt, was bestimmte Schnittstellen bedeuten. Beispielsweise könnten Sie viel Python-Code borken, indem Sie die überschreiben __file__ -Attribut (häufig verwendet, um dateiähnliche Objekte zu identifizieren) etwas anderes bedeuten.

    – Dan Lenski

    16. Juni 2014 um 19:38 Uhr

  • Das alles läuft auf den alten Witz hinaus: “Doktor, es tut weh, wenn ich das tue.” … “Dann tu das nicht.”. Unbefriedigend für jemanden, der daran gewöhnt ist, “wenn es kompiliert, läuft es”, aber deshalb entwickelte sich die Testbesessenheit aus der dynamischen Sprachwelt.

    – klack

    28. Juli 2016 um 11:46 Uhr

  • @clacke das war vor 2 jahren aber es stimmt. Ich übertreibe das Thema stark. Die Typüberprüfung im “dynamischen Raum” unterscheidet sich stark von der im “Kompilierungszeitraum”. Damit der Computer versteht, was wir von ihm wollen, muss er zur Laufzeit viel mehr unvermeidbare Arbeit leisten, als Sie es in einem schönen Kompilierzeitraum tun würden. Als ich dieses Beispiel schrieb, habe ich hauptsächlich in C und Java codiert und hatte wenig bis gar kein Verständnis für dynamischen Raum, daher schien es schlimm, dass solche Dinge passieren können, ohne dass die Möglichkeit besteht, sie durch statische Analyse zu verhindern.

    – Dmitri

    28. Juli 2016 um 11:52 Uhr

  • @clacke im Grunde ist es zu teuer, Typen zur Laufzeit strikt durchzusetzen, da ALLES ein Objekt sein muss (um von Zeichenfolgen auf jeden möglichen Typ abzubilden), und zu praktisch, um kein Ducktyping zu haben, da Ducktyping wirklich leistungsstarke Prototyping-Techniken ermöglicht, die Dinge überwinden, die das überwinden sind bei starren Schnittstellen normalerweise nur sehr schwer zu bewerkstelligen. Außerdem steht jede statische Sprache vor einem Punkt, an dem sie Ententypisierung über dynamische Bibliotheken, Auswertung und Stringifizierung oder Schnittstellen erstellen muss, und diese Dinge machen sie nicht von Natur aus böse, sondern nur sehr mächtig.

    – Dmitri

    28. Juli 2016 um 12:02 Uhr

1158460cookie-checkWas ist der kanonische Weg, um in Python nach Typ zu suchen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy