402 Stimmen

Bleibt beim Lesen einer ganzen Datei der Datei-Handle offen?

Wenn Sie eine ganze Datei mit content = open('Path/to/file', 'r').read() bleibt das Dateihandle offen, bis das Skript beendet wird? Gibt es eine präzisere Methode, um eine ganze Datei zu lesen?

627voto

Die Antwort auf diese Frage hängt ein wenig von der jeweiligen Python-Implementierung ab.

Um zu verstehen, was es damit auf sich hat, sollten Sie besonders auf den eigentlichen file Gegenstand. In Ihrem Code wird dieses Objekt nur einmal in einem Ausdruck erwähnt und ist unmittelbar nach der read() Anruf zurück.

Dies bedeutet, dass das Dateiobjekt Müll ist. Die einzige verbleibende Frage ist: "Wann wird der Garbage Collector das Dateiobjekt einsammeln?".

in CPython, das einen Referenzzähler verwendet, wird diese Art von Müll sofort bemerkt und daher auch sofort eingesammelt. Dies ist bei anderen Python-Implementierungen im Allgemeinen nicht der Fall.

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()

der die Datei immer sofort nach dem Ende des Blocks schließt, auch wenn eine Ausnahme auftritt.

Edit: Um die Sache zu präzisieren:

Andere als file.__exit__() die "automatisch" in einem der folgenden Fälle aufgerufen wird with Kontextmanager-Einstellung, die einzige andere Möglichkeit, die file.close() automatisch aufgerufen wird (d. h., wenn Sie es nicht ausdrücklich selbst aufrufen), ist über file.__del__() . Dies führt uns zu der Frage, wann die __del__() angerufen werden?

Ein korrekt geschriebenes Programm kann nicht davon ausgehen, dass Finalizer zu irgendeinem Zeitpunkt vor dem Programmende ausgeführt werden.

-- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203

Im Besonderen:

Objekte werden nie explizit zerstört; wenn sie jedoch unerreichbar werden, können sie in den Müll geworfen werden. Eine Implementierung darf die Garbage Collection verschieben oder ganz auslassen - es ist eine Frage der Implementierungsqualität, wie die Garbage Collection implementiert wird, solange keine Objekte gesammelt werden, die noch erreichbar sind.

[...]

CPython verwendet derzeit ein Referenz-Zählschema mit (optionaler) verzögerter Erkennung von zyklisch verknüpftem Müll, das die meisten Objekte sammelt, sobald sie unerreichbar werden, aber nicht garantiert, dass Müll mit zirkulären Referenzen gesammelt wird.

-- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types

(Hervorhebung von mir)

aber wie schon angedeutet, können andere Implementierungen ein anderes Verhalten aufweisen. Als Beispiel, PyPy hat 6 verschiedene Implementierungen der Müllabfuhr !

121voto

Eyal Levin Punkte 13427

Sie können verwenden pathlib .

Für Python 3.5 und höher:

from pathlib import Path
contents = Path(file_path).read_text()

Für ältere Versionen von Python verwenden Sie pathlib2 :

$ pip install pathlib2

Dann:

from pathlib2 import Path
contents = Path(file_path).read_text()

Dies ist die eigentliche read_text Umsetzung :

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()

4voto

Kirill Punkte 163

Wenn Sie die Datei Zeile für Zeile lesen müssen, um mit jeder Zeile zu arbeiten, können Sie

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

2voto

Andreas L. Punkte 1822

Anstatt den Inhalt der Datei als eine einzige Zeichenkette abzurufen, kann es praktisch sein, den den Inhalt als eine Liste aller Zeilen der Datei speichern :

with open('Path/to/file', 'r') as content_file:
    content_list = content_file.read().strip().split("\n")

Wie man sieht, muss man die verketteten Methoden hinzufügen .strip().split("\n") zu die wichtigste Antwort in diesem Thema .

Hier, .strip() entfernt lediglich Leerzeichen und Zeilenumbrüche an den Enden der gesamten Dateizeile, und .split("\n") erzeugt die eigentliche Liste, indem es die gesamte Zeichenkette der Datei an jeder Stelle aufteilt Zeilenumbruchzeichen \n .

Außerdem, kann auf diese Weise der gesamte Inhalt der Datei in einer Variablen gespeichert werden, was in manchen Fällen erwünscht sein kann, anstatt die Datei Zeile für Zeile in einer Schleife zu durchlaufen, wie es in diese vorherige Antwort .

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