Warum erfordert die Bearbeitung mehrerer Ausnahmen ein Tupel und keine Liste?

Betrachten Sie das folgende Beispiel:

def main_list(error_type): try: if error_type == 'runtime': raise RuntimeError("list error") if error_type == 'valueerror': raise ValueError("list error") except [RuntimeError, ValueError] as e: print str(e) def main_tuple(error_type): try: if error_type == 'runtime': raise RuntimeError("tuple error") if error_type == 'valueerror': raise ValueError("tuple error") except (RuntimeError, ValueError) as e: print str(e) main_tuple('runtime') main_tuple('valueerror') main_list('runtime') main_list('valueerror') 

Das Tupel ist der richtige Weg, um mehrere Exception-Typen zu behandeln. Die Verwendung einer Liste für die mehreren Ausnahmetypen wird weder behandelt noch behandelt.

Ich frage mich, warum Python-Syntax ein Tupel für mehrere Exception-Typen erfordert . Die Docs sagen, dass es ein Tupel verwendet, also vielleicht ist es einfach "nie wurde mit einer Liste anstelle eines Tupels implementiert."

Es scheint mir vernünftig, dass eine Liste auch in dieser Situation, begrifflich zumindest verwendet werden könnte.

Gibt es einen Grund, warum Python ein Tupel anstelle einer Liste für diese Situation verwendet?

2 Solutions collect form web for “Warum erfordert die Bearbeitung mehrerer Ausnahmen ein Tupel und keine Liste?”

Warum erfordert die Bearbeitung mehrerer Ausnahmen ein Tupel und keine Liste?

Die in C geschriebene Fehlerbehandlung verwendet die Typprüfung für den Spezialfall eines Tupels vor einer anderen Typprüfung und Ausnahmebehandlung, so dass mehrere Arten von Ausnahmen gefangen werden können.

Mindestens ein Python-Core-Entwickler befürwortet die Verwendung von Ausnahmebehandlung für den Kontrollfluss. Hinzufügen von Listen als zusätzlicher Typ zu überprüfen, würde gegen diese Strategie arbeiten.

Es scheint, dass das Erweitern dieses, um Sätze oder Listen zuzulassen, nicht spezifisch vom Kernentwicklungsteam angesprochen worden ist, obwohl ich mich gerne darauf beziehen werde, wenn es gefunden werden kann. Es gab eine Diskussion über die Python-Mailing-Liste , die ziemlich viel spekuliert (eine andere Antwort hier zitiert eine Antwort auf Länge).

Nach der Durchführung der folgenden Analyse, und im Zusammenhang mit der Mailing-Liste Diskussion, ich denke, die Argumentation ist offensichtlich. Ich schlage vor, nicht vorzuschlagen, andere Behälter hinzuzufügen.

Demonstration, die auflistet, versagt gegen Tupel

 >>> excs = TypeError, RuntimeError >>> lexcs = list(excs) 

Das Fangen der Tupel der Ausnahmen funktioniert:

 >>> try: ... raise TypeError('foo') ... except excs as e: ... print(e) ... foo 

Python 3

Das Fangen der Liste der Ausnahmen funktioniert nicht:

 >>> try: ... raise TypeError('foo') ... except lexcs as e: ... print(e) ... Traceback (most recent call last): File "<stdin>", line 2, in <module> TypeError: foo During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 3, in <module> TypeError: catching classes that do not inherit from BaseException is not allowed 

Python 2.7

 >>> try: ... raise TypeError('foo') ... except lexcs as e: ... print e ... Traceback (most recent call last): File "<stdin>", line 2, in <module> TypeError: foo 

Dies zeigt, dass wir die Typprüfung für den Spezialfall eines Tupels durchführen. Es würde sicherlich den Code langsamer machen, um einen anderen Typ hinzuzufügen, um zu überprüfen, und die Core-Entwickler haben gesagt, dass es eine gute Sache ist, Ausnahmebehandlung für den Kontrollfluss in Python für eine Weile jetzt zu verwenden.

Quellcodeanalyse

Eine Analyse der Quelle stimmt mit dieser obigen Schlussfolgerung überein.

Grammatik

Dies ist kein Problem für Pythons Grammatik oder Parsing. Es wird jeden Ausdruck akzeptieren. So sollte jeder Ausdruck, der zu einer Ausnahme oder einem Tupel von Ausnahmen führt, legal sein.

Zerlegung

Wenn wir eine Funktion zerlegen, die dies in Python 3 macht, sehen wir, dass es aussieht, eine Ausnahme mit einem Vergleichsvorgang anzupassen.

 >>> def catch(exceptions): ... try: ... raise Exception ... except exceptions: ... pass >>> import dis >>> dis.dis(catch) 2 0 SETUP_EXCEPT 10 (to 13) 3 3 LOAD_GLOBAL 0 (Exception) 6 RAISE_VARARGS 1 9 POP_BLOCK 10 JUMP_FORWARD 18 (to 31) 4 >> 13 DUP_TOP 14 LOAD_FAST 0 (exceptions) 17 COMPARE_OP 10 (exception match) ... 

Das führt uns in den Python-Interpreten.

Interner Kontrollfluss – CPythons Implementierungsdetails

Der CPython-Kontrollfluss prüft zuerst , ob der Wert ein Tupel ist. Wenn ja, iteriert es durch das Tupel mit Tupel-spezifischen Code – auf der Suche nach dem Wert, um eine Ausnahme zu sein:

 case PyCmp_EXC_MATCH: if (PyTuple_Check(w)) { Py_ssize_t i, length; length = PyTuple_Size(w); for (i = 0; i < length; i += 1) { PyObject *exc = PyTuple_GET_ITEM(w, i); if (!PyExceptionClass_Check(exc)) { PyErr_SetString(PyExc_TypeError, CANNOT_CATCH_MSG); return NULL; } } } else { if (!PyExceptionClass_Check(w)) { PyErr_SetString(PyExc_TypeError, CANNOT_CATCH_MSG); return NULL; } } res = PyErr_GivenExceptionMatches(v, w); 

Das Hinzufügen eines anderen Typs würde einen internen Kontrollfluss erfordern, was den Kontrollfluss innerhalb des Python-Interpreters verlangsamt.

Größen von Python-Containern

Tupel sind leichte Arrays von Zeigern . So sind Listen, aber sie können zusätzliche Platz zugewiesen werden, so dass man ihnen schnell hinzufügen kann (bis zu dem Punkt, den sie benötigen, um größer zu werden).

Sets nehmen viel mehr Platz ein, weil sie Hash-Tische sind. Sie haben sowohl einen Hash des Gegenstandes, den sie enthalten, als auch einen Zeiger auf das, auf das sie hinweisen.

Schlussfolgerung

Dies ist für die CPython Kern Entwicklung Team zu diskutieren und für die BDFL (Benevolent Diktator für das Leben) Guido van Rossum zu entscheiden.

Aber meine Schlussfolgerung ist, dass die Verlangsamung des Kontrollflusses in Python durch die Überprüfung auf andere Typen gegen die Strategie der Verwendung von Ausnahmebehandlung für den Kontrollfluss in Python-Modulen funktionieren würde.

Nach dem Überdenken durch die oben, würde ich nicht vorschlagen, dass sie dies hinzufügen.

@BrenBarn Vielen Dank für Ihren Link zur Diskussion unter https://mail.python.org/pipermail/python-list/2012-January/619107.html

Ich denke, die beste und klarste Antwort kommt von Steven D'Apranos Antwort auf https://mail.python.org/pipermail/python-list/2012-January/619120.html

Ich habe den untenstehenden Inhalt kopiert.


Stevens Antwort:

Einfachheit.

Wenn Sie auch Listen zulassen, warum erlauben Sie dann keine willkürlichen Sequenzen? Was ist mit Iteratoren, erlaubst du ihnen? Das könnte unangenehm sein, denn Iteratoren können nur einmal durchlaufen werden. Wörterbücher sind auch iterable, also, sobald Sie beliebige iterables erlauben, erhalten Sie Dicts. Das Ganze wird ein Durcheinander. Besser, um es einfach zu halten und nur einen einzelnen kanonischen Sammeltyp zuzulassen, und in Python ist dieser Typ Tupel, nicht Liste.

Tupel sind die kanonische Sammlung Art, weil sie eine Reihe von wünschenswerten Eigenschaften haben:

  • Tupel sind klein und Speicher effizient, mit der kleinsten Menge an Speicher benötigt, um ihre Elemente zu halten. Listen enthalten in der Regel einen Block von Ersatzspeicher, um Einfügungen schnell zu machen.

  • Folglich kann die virtuelle Maschine von Python schnell und effizient erstellen.

  • Tupel sind unveränderlich, also musst du dir keine Sorgen machen, dass du eine zu einer Funktion passierst und die Funktion hinter deinem Rücken modifizierst.

  • Tupel sind bestellt, für die Zeiten, wo das wichtig ist.

  • Da der typische Use-Case ist, um über die Elemente in fester Reihenfolge zu iterieren, gibt es keine Notwendigkeit, die zusätzlichen Kosten für ein Dict oder Set bezahlen.

  • Tupel sind einfach zu schreiben: Im Allgemeinen brauchen Sie nur Kommas zwischen Items. Manchmal, um Unklarheiten zu vermeiden oder den Vorrang der Berechnung zu ändern, benötigen Sie auch runde Klammern (Klammern für Amerikaner). Außer klauseln sind eine dieser Zeiten.

  • Frozensets und Sets sind aus historischen Gründen ausgeschlossen: sie existierten nicht bis Python 2.3. Außerdem was würdest du lieber schreiben?

    ("Abc", "def") frozenset ([abc "," def "])

  • Sets und Listen sind ausgeschlossen, weil sie veränderlich sind, beide erfordern viel mehr Speicher, und Sets haben eine schwerere rechnerische Belastung.

Letzterer macht mich sinnvoller für mich – "fangen alle Ausnahmetypen in einer Liste" im Gegensatz zu "Fangen Sie diese Einzelsache aus drei Ausnahmetypen".

Dann arbeiten Sie unter einem Missverständnis. Du hast kein Tupel gefangen, weil Tupel niemals geworfen werden. Sie fangen irgendwelche der Ausnahmen, die in diesem Tupel enthalten sind.

Beide Listen und Tupel sind einzelne Dinge in sich selbst. Beide Listen und Tupel sind Container:

Eine Liste ist eine einzige Sache, die andere Dinge enthält.

Ein Tupel ist eine einzige Sache, die andere Dinge enthält.

  • Ist es möglich, Variable in Python zu ändern, die im äußeren, aber nicht globalen Bereich ist?
  • So konvertieren Sie die Liste der JSON-Frames in den JSON-Frame
  • Wie man läuft python script wie pm2 für nodejs
  • Python Windows `msvcrt.getch ()` erkennt nur jeden 3. Keypress?
  • Subtrahiere ein Jahr aus einer datetime Spalte in Pandas
  • Brauchen Sie Hilfe, um Gromac-Datei in Python zu lesen
  • Wie man den Klang aus dem Text als mp3 oder Welle in Python produziert
  • Warum leseline.read_history_file gib mir 'IOError: [Errno 2] Keine solche Datei oder Verzeichnis'
  • So initialisieren Sie verschachtelte Wörterbücher in Python
  • Mit python und PIL wie kann ich einen Block von Text in einem Bild packen?
  • NZEC - Runtime Error in Python
  • Python ist die beste Programmiersprache der Welt.