In prähistorischen Zeiten (Python 1.4) haben wir:
fp = open('filename.txt')
while 1:
line = fp.readline()
if not line:
break
print line
Nach Python 2.1 haben wir Folgendes getan:
for line in open('filename.txt').xreadlines():
print line
bevor wir das praktische Iterator-Protokoll in Python 2.3 erhielten und Folgendes tun konnten:
for line in open('filename.txt'):
print line
Ich habe einige Beispiele mit der ausführlicheren gesehen:
with open('filename.txt') as fp:
for line in fp:
print line
Ist dies die bevorzugte Methode für die Zukunft?
[Bearbeiten] Ich verstehe, dass die with-Anweisung das Schließen der Datei sicherstellt ... aber warum ist das nicht im Iteratorprotokoll für Dateiobjekte enthalten?
python
python-3.x
python-2.7
thebjorn
quelle
quelle
Antworten:
Es gibt genau einen Grund, warum Folgendes bevorzugt wird:
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
with
Block, 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
with
Block verwenden.Bonus-Frage
(Hören Sie jetzt auf zu lesen, wenn Sie nur an den objektiven Aspekten der Frage interessiert sind.)
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
with
Block 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:
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.
quelle
with
gibt Ihnen jedoch die Gewissheit, dass es immer noch eine bewährte Methode ist.Ja,
ist der Weg zu gehen.
Es ist nicht ausführlicher. Es ist sicherer.
quelle
Wenn Sie durch die zusätzliche Zeile ausgeschaltet sind, können Sie eine Wrapper-Funktion wie folgt verwenden:
In Python 3.3
yield from
würde die Anweisung dies noch kürzer machen:quelle
quelle