Verwenden der Python-Anweisung "with" mit dem Block "try-without"

95

Ist dies der richtige Weg, um die Python-Anweisung "with" in Kombination mit einem Try-Except-Block zu verwenden?:

try:
    with open("file", "r") as f:
        line = f.readline()
except IOError:
    <whatever>

Wenn ja, dann unter Berücksichtigung der alten Vorgehensweise:

try:
    f = open("file", "r")
    line = f.readline()
except IOError:
    <whatever>
finally:
    f.close()

Ist der Hauptvorteil der "with" -Anweisung hier, dass wir drei Codezeilen entfernen können? Es scheint mir für diesen Anwendungsfall nicht so überzeugend zu sein (obwohl ich verstehe, dass die "with" -Anweisung andere Verwendungszwecke hat).

EDIT: Ist die Funktionalität der beiden oben genannten Codeblöcke identisch?

EDIT2: Die ersten Antworten sprechen allgemein über die Vorteile der Verwendung von "mit", aber diese scheinen hier von geringem Nutzen zu sein. Wir alle haben f.close () jahrelang explizit aufgerufen (oder hätten es auch tun sollen). Ich nehme an, ein Vorteil ist, dass schlampige Codierer von der Verwendung von "with" profitieren.

gaefan
quelle
Für mich ist es ein guter Grund, 'with' zu verwenden, wenn ich nicht daran denken muss, () Dinge in einer finally-Anweisung zu schließen. Ich habe gesehen, dass viel Code seine Ressourcen nicht schließen konnte. Und 'mit' hat keine Nachteile, soweit ich sehen kann.
Raúl Salinas-Monteagudo

Antworten:

138
  1. Die beiden von Ihnen angegebenen Codeblöcke sind nicht gleichwertig
  2. Der Code, den Sie als alte Vorgehensweise beschrieben haben, weist einen schwerwiegenden Fehler auf: Falls das Öffnen der Datei fehlschlägt, erhalten Sie eine zweite Ausnahme in der finallyKlausel, da diese fnicht gebunden ist.

Der entsprechende alte Stilcode wäre:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

Wie Sie sehen können, kann die withAnweisung die Fehleranfälligkeit verringern. In neueren Versionen von Python (2.7, 3.1) können Sie auch mehrere Ausdrücke in einer withAnweisung kombinieren . Beispielsweise:

with open("input", "r") as inp, open("output", "w") as out:
    out.write(inp.read())

Außerdem halte ich es persönlich für eine schlechte Angewohnheit, Ausnahmen so früh wie möglich zu erwischen. Dies ist nicht der Zweck von Ausnahmen. Wenn die E / A-Funktion, die fehlschlagen kann, Teil einer komplizierteren Operation ist, sollte der IOError in den meisten Fällen die gesamte Operation abbrechen und daher auf einer äußeren Ebene behandelt werden. Mit withAnweisungen können Sie alle diese try...finallyAnweisungen auf inneren Ebenen entfernen.

Bernd Petersohn
quelle
7

Wenn der Inhalt des finallyBlocks durch die Eigenschaften des zu öffnenden Dateiobjekts bestimmt wird, warum sollte der Implementierer des Dateiobjekts nicht derjenige sein, der den finallyBlock schreibt ? Das ist der Vorteil derwith Anweisung, viel mehr als das Speichern von drei Codezeilen in dieser speziellen Instanz.

Und ja, die Art withund Weise, wie Sie kombiniert haben, try-exceptist so ziemlich die einzige Möglichkeit, dies zu tun, da außergewöhnliche Fehler, die in der openAnweisung selbst verursacht werden, nicht im withBlock abgefangen werden können .

Peter Milley
quelle
1

Ich denke, Sie haben es falsch gemacht, wenn Sie mit "mit" sagen, dass es nur Zeilen reduziert. Es führt tatsächlich die Initialisierung durch und behandelt das Herunterfahren.

In Ihrem Fall tut "mit"

  • öffne einen Ordner,
  • seinen Inhalt verarbeiten und
  • Stellen Sie sicher, dass Sie es schließen.

Hier ist ein Link zum Verständnis der "with" -Anweisung: http://effbot.org/zone/python-with-statement.htm

Bearbeiten: Ja, Ihre Verwendung von "mit" ist korrekt und die Funktionalität beider Codeblöcke ist identisch. Frage, warum "mit" verwendet werden soll? Es ist wegen der Vorteile, die Sie damit erhalten. wie du erwähnt hast über versehentlich fehlendes f.close ().

YoK
quelle
-4

Der pythonischere Weg für die folgenden Codes ist:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

try:
    f = open("file", "r")
except IOError:
    <whatever>
else:
    f.close()
Leo Liu
quelle
1
Ich habe die Code-Formatierung für Sie hinzugefügt. es erleichtert das Lesen. Aber vielleicht möchten Sie noch einmal überprüfen, ob ich die Einrückung nicht gebrochen habe.
Andrewsi
2
Nein, Ihre Version funktioniert nicht wie der Originalcode. Selbst wenn Sie den fehlenden readline()Aufruf hinzufügen , schließt Ihre Version die Datei nicht, wenn das readline()Ergebnis zu einem führt IOError.
Aleksi Torhamo