Es gibt genau einen Grund, warum Folgendes bevorzugt wird:
with open('filename.txt') as fp:
for line in fp:
print line
Wir alle sind verwöhnt von CPythons relativ deterministischem Referenzzählschema für die Speicherbereinigung. Andere hypothetische Implementierungen von Python schließen die Datei nicht unbedingt "schnell genug" ohne den withBlock, wenn sie ein anderes Schema verwenden, um Speicher zurückzugewinnen.
In einer solchen Implementierung wird vom Betriebssystem möglicherweise der Fehler "Zu viele Dateien öffnen" angezeigt, wenn Ihr Code Dateien schneller öffnet, als der Garbage Collector Finalizer für verwaiste Dateihandles aufruft. Die übliche Problemumgehung besteht darin, den GC sofort auszulösen. Dies ist jedoch ein böser Hack und muss von jeder Funktion ausgeführt werden, bei der der Fehler auftreten kann, einschließlich derjenigen in Bibliotheken. Was ein Alptraum.
Oder Sie könnten einfach den withBlock verwenden.
Bonus-Frage
(Hören Sie jetzt auf zu lesen, wenn Sie nur an den objektiven Aspekten der Frage interessiert sind.)
Warum ist das nicht im Iteratorprotokoll für Dateiobjekte enthalten?
Dies ist eine subjektive Frage zum API-Design, daher habe ich eine subjektive Antwort in zwei Teilen.
Auf der Darmebene fühlt sich dies falsch an, da das Iterator-Protokoll zwei separate Dinge ausführt - über Zeilen iterieren und das Dateihandle schließen - und es oft eine schlechte Idee ist, eine einfach aussehende Funktion zwei Aktionen ausführen zu lassen. In diesem Fall fühlt es sich besonders schlecht an, da sich Iteratoren quasi funktional und wertbasiert auf den Inhalt einer Datei beziehen, die Verwaltung von Dateihandles jedoch eine völlig separate Aufgabe ist. Beide unsichtbar zu einer Aktion zusammenzufassen, ist für Menschen, die den Code lesen, überraschend und erschwert es, über das Programmverhalten nachzudenken.
Andere Sprachen sind im Wesentlichen zu dem gleichen Schluss gekommen. Haskell flirtete kurz mit dem sogenannten "Lazy IO", mit dem Sie eine Datei durchlaufen und automatisch schließen können, wenn Sie am Ende des Streams angelangt sind. Es wird jedoch fast allgemein davon abgeraten, Lazy IO in Haskell und Haskell zu verwenden Benutzer sind größtenteils zu einer expliziteren Ressourcenverwaltung wie Conduit übergegangen, die sich eher wie der withBlock in Python verhält .
Auf technischer Ebene gibt es einige Dinge, die Sie möglicherweise mit einem Dateihandle in Python tun möchten, die nicht so gut funktionieren würden, wenn die Iteration das Dateihandle schließen würde. Angenommen, ich muss die Datei zweimal durchlaufen:
with open('filename.txt') as fp:
for line in fp:
...
fp.seek(0)
for line in fp:
...
Obwohl dies ein weniger häufiger Anwendungsfall ist, bedenken Sie die Tatsache, dass ich möglicherweise gerade die drei Codezeilen unten zu einer vorhandenen Codebasis hinzugefügt habe, die ursprünglich die oberen drei Zeilen hatte. Wenn die Datei durch Iteration geschlossen würde, wäre ich dazu nicht in der Lage. Wenn Sie also Iteration und Ressourcenverwaltung getrennt halten, können Sie einfacher Codeblöcke in einem größeren, funktionierenden Python-Programm zusammenstellen.
Die Kompositionsfähigkeit ist eines der wichtigsten Usability-Merkmale einer Sprache oder API.