Antworten:
Die Antwort auf diese Frage hängt etwas von der jeweiligen Python-Implementierung ab.
Um zu verstehen, worum es geht, achten Sie besonders auf das eigentliche file
Objekt. In Ihrem Code wird dieses Objekt nur einmal in einem Ausdruck erwähnt und kann unmittelbar nach der read()
Rückkehr des Aufrufs nicht mehr aufgerufen werden.
Dies bedeutet, dass das Dateiobjekt Müll ist. Die einzige verbleibende Frage lautet: "Wann sammelt der Garbage Collector das Dateiobjekt?".
In CPython, das einen Referenzzähler verwendet, wird diese Art von Müll sofort bemerkt und daher sofort gesammelt. Dies gilt im Allgemeinen nicht für andere Python-Implementierungen.
Eine bessere Lösung, um sicherzustellen, dass die Datei geschlossen ist, ist dieses Muster:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
Dadurch wird die Datei immer sofort nach dem Ende des Blocks geschlossen. auch wenn eine Ausnahme auftritt.
Bearbeiten: Um einen genaueren Punkt darauf zu setzen:
Abgesehen davon file.__exit__()
, dass dies in einer with
Kontextmanagereinstellung "automatisch" aufgerufen wird , erfolgt die einzige andere Möglichkeit, file.close()
die automatisch aufgerufen wird (dh nicht explizit selbst aufruft), über file.__del__()
. Dies führt uns zu der Frage, wann __del__()
angerufen wird.
Ein korrekt geschriebenes Programm kann nicht davon ausgehen, dass Finalizer jemals vor dem Beenden des Programms ausgeführt werden.
- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203
Bestimmtes:
Objekte werden niemals explizit zerstört. Wenn sie jedoch nicht mehr erreichbar sind, können sie durch Müll gesammelt werden. Eine Implementierung kann die Speicherbereinigung verschieben oder ganz weglassen ist eine Frage der Implementierungsqualität, wie die Speicherbereinigung implementiert wird, solange keine Objekte erfasst werden, die noch erreichbar sind.
[...]
CPython verwendet derzeit ein Referenzzählschema mit (optionaler) verzögerter Erkennung von zyklisch verknüpftem Müll, bei dem die meisten Objekte gesammelt werden, sobald sie nicht mehr erreichbar sind. Es wird jedoch nicht garantiert, dass Müll mit Zirkelreferenzen gesammelt wird.
- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(Hervorhebung von mir)
Wie es jedoch nahelegt, können andere Implementierungen ein anderes Verhalten aufweisen. Als Beispiel PyPy hat 6 verschiedene Garbage - Collection - Implementierungen !
__exit__()
In solchen Fällen nicht anzurufen, klingt nach einem Konstruktionsfehler.
try
/ finally
fummelig und die sehr häufige Nützlichkeit von Bereinigungshandlern, die with
löst. Der Unterschied zwischen "explizit schließen" und "verwalten mit with
" besteht darin, dass der Exit-Handler auch dann aufgerufen wird, wenn eine Ausnahme ausgelöst wird. Sie könnten das close()
in eine finally
Klausel with
einfügen , aber das unterscheidet sich nicht wesentlich von der Verwendung , etwas unordentlicher (3 zusätzliche Zeilen anstelle von 1) und etwas schwieriger, genau das Richtige zu finden.
with foo() as f: [...]
es im Grunde das gleiche ist wie f = foo()
, f.__enter__()
[...] und f.__exit__()
mit Ausnahmen behandelt , so dass __exit__
das immer aufgerufen wird. Die Datei wird also immer geschlossen.
Sie können pathlib verwenden .
Für Python 3.5 und höher:
from pathlib import Path
contents = Path(file_path).read_text()
Verwenden Sie für ältere Versionen von Python pathlib2 :
$ pip install pathlib2
Dann:
from pathlib2 import Path
contents = Path(file_path).read_text()
Dies ist die eigentliche read_text
Implementierung :
def read_text(self, encoding=None, errors=None):
"""
Open the file in text mode, read it, and close the file.
"""
with self.open(mode='r', encoding=encoding, errors=errors) as f:
return f.read()
Nun, wenn Sie die Datei Zeile für Zeile lesen müssen, um mit jeder Zeile zu arbeiten, können Sie verwenden
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
Oder noch besser:
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
Anstatt den Dateiinhalt als einzelne Zeichenfolge abzurufen, kann es nützlich sein, den Inhalt als Liste aller Zeilen zu speichern, die die Datei enthält :
with open('Path/to/file', 'r') as content_file:
content_list = content_file.read().strip().split("\n")
Wie zu sehen ist, müssen die verketteten Methoden .strip().split("\n")
zur Hauptantwort in diesem Thread hinzugefügt werden .
Hier, .strip()
nur Leerzeichen und Zeilenumbrüche an den Enden der gesamten Dateizeichenfolge entfernt und .split("\n")
die eigentliche Liste erstellt, indem die gesamte Dateizeichenfolge an jedem Zeilenumbruchzeichen aufgeteilt wird \ n .
Darüber hinaus kann auf diese Weise der gesamte Dateiinhalt in einer Variablen gespeichert werden, was in einigen Fällen erwünscht sein kann, anstatt die Datei zeilenweise zu durchlaufen, wie in dieser vorherigen Antwort ausgeführt .