563 Stimmen

Warum brauchen wir die "finally"-Klausel in Python?

Ich bin mir nicht sicher, warum wir finally en try...except...finally Erklärungen. Meiner Meinung nach ist dieser Codeblock

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

ist das Gleiche mit diesem hier, das finally :

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

Habe ich etwas verpasst?

12voto

Eugene Yarmash Punkte 130008

Wie in der Dokumentation die finally Klausel ist dazu gedacht, Aufräumaktionen zu definieren, die ausgeführt werden müssen unter allen Umständen .

Si finally vorhanden ist, gibt es einen "Aufräum-Handler" an. Die Website try Klausel ausgeführt wird, einschließlich aller except y else Klauseln. Wenn eine Ausnahme in einer der Klauseln auftritt und nicht behandelt wird, wird die wird die Ausnahme vorübergehend gespeichert. Die finally Klausel ausgeführt wird. Wenn eine gespeicherte Ausnahme auftritt, wird sie am Ende der finally Klausel.

Ein Beispiel:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

Wie Sie sehen können, ist die finally Klausel wird in jedem Fall ausgeführt. Die TypeError die durch die Teilung zweier Zeichenketten entsteht, wird nicht von der except Klausel und erhöhte daher erneut nach der finally Klausel ausgeführt worden ist.

In realen Anwendungen ist die finally-Klausel nützlich, um externe Ressourcen (wie Dateien oder Netzwerkverbindungen) freizugeben, unabhängig davon, ob die Nutzung der Ressource erfolgreich war.

8voto

Sven Marnach Punkte 525472

Die Codeblöcke sind nicht gleichwertig. Die finally Klausel wird auch ausgeführt, wenn run_code1() eine andere Ausnahme auslöst als TypeError , oder wenn run_code2() eine Ausnahme auslöst, während other_code() in der ersten Version würde in diesen Fällen nicht ausgeführt werden.

7voto

mhawke Punkte 79590

Was passiert in Ihrem ersten Beispiel, wenn run_code1() löst eine Ausnahme aus, die nicht TypeError ? ... other_code() wird nicht ausgeführt.

Vergleichen Sie das mit dem finally: Version: other_code() wird garantiert ausgeführt, auch wenn eine Ausnahme ausgelöst wird.

5voto

nurettin Punkte 10395

Als ich Delphi einige Jahre lang professionell einsetzte, lernte ich, meine Bereinigungsroutinen mit finally zu sichern. Delphi erzwingt quasi die Verwendung von finally, um alle vor dem try-Block erstellten Ressourcen zu bereinigen, damit kein Speicherleck entsteht. So funktioniert es auch in Java, Python und Ruby.

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

und die Ressource wird bereinigt, unabhängig davon, was Sie zwischen try und finally tun. Es wird auch nicht aufgeräumt, wenn die Ausführung nie die try Block. (d.h.. create_resource selbst eine Ausnahme auslöst). Das macht Ihren Code "ausnahmesicher".

Die Frage, warum man einen Finally-Block braucht, stellt sich nicht in allen Sprachen. In C++ gibt es automatisch aufgerufene Destruktoren, die eine Bereinigung erzwingen, wenn eine Ausnahme den Stack aufrollt. Ich denke, dies ist ein Schritt in Richtung sauberer Code im Vergleich zu try...finally-Sprachen.

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.

4voto

Brad Johnson Punkte 1598

Schließlich kann auch verwendet werden, wenn Sie "optionalen" Code vor dem Code für Ihre Hauptarbeit ausführen wollen und dieser optionale Code aus verschiedenen Gründen fehlschlagen kann.

Im folgenden Beispiel wissen wir nicht genau, welche Art von Ausnahmen store_some_debug_info werfen könnte.

Wir könnten fliehen:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

Die meisten Linters werden sich jedoch darüber beschweren, dass die Ausnahmeregelung zu vage formuliert ist. Außerdem, da wir uns dafür entscheiden, nur pass für Fehler, die except Block keinen wirklichen Mehrwert bringt.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

Der obige Code hat die gleiche Wirkung wie der erste Codeblock, ist aber übersichtlicher.

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