1822 Stimmen

Was ist der kanonische Weg, um für Typ in Python zu überprüfen?

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

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

16 Stimmen

Ich glaube, Herr Coombs übersieht Beispiele wie nicht-JSON serialisierbare Klassen. Wenn man einen großen Datenblock durch eine Funktion schickt (deren Code man nicht beeinflussen kann), möchte man vielleicht bestimmte Teile dieser Daten in ein <str> konvertieren, bevor man sie weitergibt. Zumindest ist das so I landete auf dieser Seite...

7 Stimmen

Es scheint, dass der häufigste Grund für diese Frage darin besteht, dass man zwischen Zeichenketten und Iterablen von Zeichenketten unterscheiden möchte. Dies ist eine knifflige Frage, weil Strings sind Iterabilen von Zeichenketten - eine Ein-Zeichen-Zeichenkette ist sogar eine Folge von sich selbst (als ich das letzte Mal nachgesehen habe - man sollte sich wahrscheinlich nicht darauf verlassen). Aber würde jemand jemals Verwendung für etwas String-ähnliches haben? Oui . Die Antwort auf die Frage "Wie unterscheide ich zwischen Zeichenketten und anderen Iterabilen von Zeichenketten?" ist also richtig: "Das hängt davon ab, was Sie tun wollen" :-D

7 Stimmen

Python-Typ-Annotationen sind jetzt eine Sache. Werfen Sie einen Blick auf mypy

7voto

Die akzeptierte Antwort beantwortet die Frage, indem sie die Antworten auf die gestellten Fragen liefert.

F: Wie kann man am besten prüfen, ob ein bestimmtes Objekt von einem bestimmten Typ ist? Wie wäre es zu prüfen, ob das Objekt von einem bestimmten Typ erbt?

A: Verwendung isinstance, issubclass, type auf der Grundlage von Typen zu prüfen.

Wie in anderen Antworten und Kommentaren jedoch schnell deutlich wird, steckt hinter der Idee der "Typüberprüfung" in Python noch viel mehr. Seit der Einführung von Python 3 und Typ-Hinweise hat sich ebenfalls viel verändert. Im Folgenden gehe ich auf einige der Schwierigkeiten bei der Typprüfung, der Duck-Typisierung und der Ausnahmebehandlung ein. Für diejenigen, die der Meinung sind, dass eine Typüberprüfung nicht notwendig ist (normalerweise ist sie es nicht, aber wir sind ja hier), zeige ich auch auf, wie stattdessen Typ-Hinweise verwendet werden können.

Typenprüfung

Eine Typüberprüfung ist in Python nicht immer sinnvoll. Betrachten Sie das folgende Beispiel:

def sum(nums):
    """Expect an iterable of integers and return the sum."""
    result = 0
    for n in nums:
        result += n
    return result

Um zu prüfen, ob die Eingabe eine Iterable von ganzen Zahlen ist, stoßen wir auf ein großes Problem. Die einzige Möglichkeit zu prüfen, ob jedes Element eine ganze Zahl ist, wäre eine Schleife, um jedes Element zu prüfen. Wenn wir jedoch den gesamten Iterator in einer Schleife durchlaufen, bleibt nichts für den vorgesehenen Code übrig. In einer solchen Situation haben wir zwei Möglichkeiten.

  1. In der Schleife prüfen.

  2. Prüfen Sie vorher, aber bewahren Sie alles so auf, wie wir es prüfen.

Option 1 hat den Nachteil, dass sie unseren Code verkompliziert, insbesondere wenn wir an vielen Stellen ähnliche Prüfungen durchführen müssen. Sie zwingt uns, die Typüberprüfung vom Anfang der Funktion nach überall verwenden wir die Iterable in unserem Code.

Option 2 hat den offensichtlichen Nachteil, dass sie den gesamten Zweck von Iteratoren zunichte macht. Der ganze Sinn besteht darin, die Daten nicht zu speichern, weil wir das nicht brauchen sollten.

Man könnte auch denken, dass die Überprüfung, ob die Überprüfung aller Elemente ist zu viel, dann vielleicht können wir nur prüfen, ob die Eingabe selbst ist vom Typ iterable, aber es gibt nicht wirklich eine iterable Basisklasse. Jeder Typ, der __iter__ ist iterierbar.

Ausnahmebehandlung und Duck Typing

Ein alternativer Ansatz wäre, ganz auf die Typüberprüfung zu verzichten und sich stattdessen auf die Behandlung von Ausnahmen und die Typisierung von Enten zu konzentrieren. Das heißt, Sie verpacken Ihren Code in einen try-except-Block und fangen alle Fehler ab, die auftreten. Alternativ können Sie auch gar nichts tun und Ausnahmen auf natürliche Weise aus Ihrem Code entstehen lassen.

Hier ist eine Möglichkeit, eine Ausnahme abzufangen.

def sum(nums):
    """Try to catch exceptions?"""
    try:
        result = 0
        for n in nums:
            result += n
        return result
    except TypeError as e:
        print(e)

Im Vergleich zu den bisherigen Möglichkeiten ist dies sicherlich besser. Wir prüfen, während wir den Code ausführen. Wenn es eine TypeError irgendwo, werden wir es wissen. Wir müssen nicht überall, wo wir die Eingabe in einer Schleife durchlaufen, eine Prüfung durchführen. Und wir müssen die Eingabe nicht speichern, wenn wir sie durchlaufen.

Außerdem ermöglicht dieser Ansatz die Typisierung von Enten. Anstatt zu prüfen, ob specific types sind wir dazu übergegangen, zu prüfen, ob specific behaviors und suchen, wenn sich die Eingabe nicht wie erwartet verhält (in diesem Fall durchlaufen wir eine Schleife nums und die Möglichkeit, die n ).

Doch genau die Gründe, die die Ausnahmebehandlung so angenehm machen, können auch ihr Verhängnis sein.

  1. A float ist kein int aber sie erfüllt die Verhalten Anforderungen an die Arbeit.

  2. Es ist auch eine schlechte Praxis, den gesamten Code mit einem try-except-Block zu umhüllen.

Auf den ersten Blick mag dies nicht als Problem erscheinen, aber hier sind einige Gründe, die Ihre Meinung ändern könnten.

  1. Ein Benutzer kann nicht mehr erwarten, dass unsere Funktion eine int wie vorgesehen. Dies kann den Code an anderer Stelle brechen.

  2. Da Ausnahmen aus einer Vielzahl von Quellen stammen können, kann die Verwendung von try-except für den gesamten Codeblock dazu führen, dass Ausnahmen abgefangen werden, die Sie nicht beabsichtigt haben. Wir wollten nur prüfen, ob nums war iterierbar und hatte ganzzahlige Elemente.

  3. Im Idealfall möchten wir die Ausnahmen, die unsere Codegeneratoren erzeugen, abfangen und stattdessen informativere Ausnahmen auslösen. Es ist nicht lustig, wenn eine Ausnahme aus dem Code eines anderen ausgelöst wird, ohne eine andere Erklärung als eine Zeile, die man nicht geschrieben hat, und dass einige TypeError aufgetreten.

Um die Ausnahmebehandlung als Reaktion auf die obigen Punkte zu beheben, würde unser Code dann zu dieser... Abscheulichkeit werden.

def sum(nums):
    """
    Try to catch all of our exceptions only.
    Re-raise them with more specific details.
    """
    result = 0

    try:
        iter(nums)
    except TypeError as e:
        raise TypeError("nums must be iterable")

    for n in nums:
        try:
            result += int(n)
        except TypeError as e:
            raise TypeError("stopped mid iteration since a non-integer was found")

    return result

Sie können sich denken, worauf das hinausläuft. Je mehr wir versuchen, Dinge "richtig" zu überprüfen, desto schlechter sieht unser Code aus. Verglichen mit dem ursprünglichen Code ist dieser überhaupt nicht lesbar.

Man könnte argumentieren, dass dies vielleicht ein bisschen extrem ist. Aber andererseits ist dies nur ein sehr einfaches Beispiel. In der Praxis ist Ihr Code wahrscheinlich viel komplizierter als dies.

Typ-Hinweise

Wir haben gesehen, was passiert, wenn wir versuchen, unser kleines Beispiel so zu ändern, dass die Typenprüfung aktiviert wird. Anstatt sich auf den Versuch zu konzentrieren, bestimmte Typen zu erzwingen, bietet das Type Hinting eine Möglichkeit, den Benutzern die Typen klar zu machen.

from typing import Iterable

def sum(nums: Iterable[int]) -> int:
    result = 0
    for n in nums:
        result += n
    return result

Hier sind einige Vorteile der Verwendung von Typ-Hinweisen.

  • Der Code sieht jetzt wirklich gut aus!

  • Die statische Typanalyse kann von Ihrem Editor durchgeführt werden, wenn Sie Typ-Hinweise verwenden!

  • Sie werden in der Funktion/Klasse gespeichert, so dass sie dynamisch verwendet werden können, z. B. typeguard y dataclasses .

  • Sie werden für Funktionen angezeigt, wenn Sie help(...) .

  • Sie brauchen nicht zu prüfen, ob Ihr Eingabetyp auf der Grundlage einer Beschreibung oder, schlimmer noch, deren Fehlen richtig ist.

  • Sie können einen Hinweis basierend auf Struktur z. B. "Hat es dieses Attribut?", ohne dass der Benutzer eine Unterklassifizierung vornehmen muss.

Der Nachteil der Tipphilfe?

  • Typ-Hinweise sind nichts anderes als Syntax und spezieller Text für sich genommen. Das ist nicht dasselbe wie eine Typenprüfung .

Mit anderen Worten, es beantwortet die Frage nicht wirklich, weil es keine Typüberprüfung bietet. Wenn Sie jedoch wegen der Typenprüfung hier sind, dann sollten Sie sollte auch ein Typ-Hinweis sein. Natürlich, wenn Sie zu dem Schluss gekommen sind, dass Typprüfung nicht wirklich notwendig ist, aber Sie wollen einen gewissen Anschein von Typisierung, dann Typ Hinweise sind für Sie.

6voto

Chris Barker Punkte 539

Für Hugo:

Sie meinen wahrscheinlich list statt array Sie wollen nicht wissen, ob das betreffende Objekt eine Liste ist, sondern ob es sich um eine Art Sequenz oder ein einzelnes Objekt handelt. Versuchen Sie also, es wie eine Sequenz zu verwenden.

Sagen wir, Sie wollen das Objekt zu einer bestehenden Sequenz hinzufügen, oder, wenn es sich um eine Sequenz von Objekten handelt, sie alle hinzufügen

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

Ein Trick dabei ist, wenn Sie mit Zeichenketten und/oder Zeichenkettenfolgen arbeiten - das ist knifflig, denn eine Zeichenkette wird oft als einzelnes Objekt betrachtet, ist aber auch eine Folge von Zeichen. Noch schlimmer ist, dass es sich in Wirklichkeit um eine Folge von Zeichenketten mit einfacher Länge handelt.

Ich entscheide mich in der Regel dafür, meine API so zu gestalten, dass sie nur entweder einen einzelnen Wert oder eine Sequenz akzeptiert - das macht die Sache einfacher. Es ist nicht schwer, eine [ ] um Ihren Einzelwert herum, wenn Sie ihn bei Bedarf übergeben.

(Allerdings kann dies bei Zeichenketten zu Fehlern führen, da sie wie Sequenzen aussehen (sind).)

-5voto

Ultrablendz Punkte 451

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

-13voto

cherah30 Punkte 476

Meiner Meinung nach ist es am besten, wenn Sie Ihre Variablen gut eintippen. Sie können dies tun, indem Sie die "typing" Bibliothek.

from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313`)

Ver https://docs.python.org/3/library/typing.html .

4 Stimmen

Aber Sie haben nirgendwo einen Scheck vorgelegt, oder? Wenn ja, können Sie bitte erklären, wo Sie in dem von Ihnen angegebenen Code nach dem Typ suchen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X