2009-09-03 10 views
10

Zum Inhalt einer Datei lesen:Datei geöffnet: Ist das ein schlechter Python-Stil?

data = open(filename, "r").read() 

Die geöffnete Datei sofort überall referenziert nicht mehr fortgesetzt wird, so dass die Objektdatei schließlich schließen wird ... und es keine anderen Programme, die sie mit beeinflussen sollte, da die Datei nur zum Lesen geöffnet, nicht zum Schreiben.

EDIT: Das hat mich tatsächlich in einem Projekt gebissen, das ich schrieb - es veranlasste mich, this Frage zu stellen. Dateiobjekte werden nur bereinigt, wenn nicht genügend Arbeitsspeicher zur Verfügung steht und nicht mehr, wenn keine Dateihandles mehr vorhanden sind. Wenn Sie dies zu oft tun, könnten Sie am Ende keine Dateideskriptoren mehr haben und Ihre E/A-Versuche beim Öffnen von Dateien veranlassen, Ausnahmen auszulösen.

+3

Beachten Sie, dass dies die gesamte Datei in den Speicher liest, egal wie groß sie ist. Stellen Sie also sicher, dass es sich um eine Datei handelt, mit der Sie umgehen können. Ansonsten stimme ich den Antworten zu. – balpha

+0

@balpha: Aber die Antworten sind widersprüchlich. ;) (Ich nehme an, Sie haben den Kommentar gemacht, bevor alle Antworten eingingen.) –

Antwort

29

Nur für das Protokoll: Dies ist nur etwas länger, und schließt die Datei sofort:

from __future__ import with_statement 

with open(filename, "r") as f: 
    data = f.read() 
+4

+1 Ich habe den Import hinzugefügt, nur für den Fall, dass sie Python 2.5 verwenden :) –

+0

Eine Frage zum Follow-up-Stil: Ist es wirklich schrecklich, * mit open ("t1.py", "r") als f: f zu tun. read() * alles auf einer Zeile? Ich weiß, dass es nicht so gut lesbar ist, aber so oft ist das Einlesen der Datei eine sehr einfache Sache, und dem nächsten Typ, der den Code liest, ist es egal, wie du es gemacht hast. –

+0

@Jenn D: Ein Punkt des 'mit' ist es, die gesamte Verarbeitung in einen ordentlichen Bereich zu beschränken. Wenn man 'mit open() als f: f.read()' in eine Zeile setzt, wird der Scoping-Zweck von 'with' irgendwie zunichte gemacht. –

3

Nein, es ist völlig in Ordnung Python-Stil IMO, wie Sie argumentieren.

Update: Es gibt eine Menge Kommentare darüber, ob Dateiobjekte sofort aufgeräumt werden oder nicht. Anstatt zu spekulieren, habe ich etwas gegraben. Hier ist, was ich sehe:


Von einem Kommentar in Python object.h:

Die Makros Py_INCREF (op) und Py_DECREF (op) verwendet werden, zu erhöhen oder Abnahme Referenzzähler. Py_DECREF ruft die deallocator Objekt Funktion, wenn die refcount fällt auf 0

Blick in Python fileobject.c:

Die Funktionstabelle für Datei Punkte Objekte file_dealloc funktionieren. Diese Funktion ruft close_the_file auf, was wiederum die Datei schließt.


So scheint es sinnvoll zu sagen, dass im Moment auf CPython, wenn es keine mehr Verweise auf ein Dateiobjekt gibt, es ohne Verzögerung geschlossen wird. Wenn du denkst, dass diese Interpretation falsch ist, poste bitte einen Kommentar, der angibt, warum du dich so fühlst.

+0

Vernünftig, aber die OS-Ressourcen sind möglicherweise nicht so vollständig verfügbar, wie Sie möchten. Wenn Sie beispielsweise versuchen, die Datei sofort nach dem Lesen zu entfernen, funktioniert das möglicherweise nicht, da die Betriebssystemressourcen von den zugrunde liegenden C-Bibliotheken gehalten werden, auch wenn das Python-Dateiobjekt als Garbage Collected erfasst wurde. Bis das Betriebssystem denkt, dass die Datei nicht mehr verwendet wird, können Sie sie möglicherweise nicht löschen. –

+0

@ S. Lott: sagen Sie, dass ein Garbage-Collected 'Datei'-Objekt nicht geschlossen ist (damit das OS weiß, dass es nicht mehr benutzt wird)? Ich würde * erwarten *, dass das Löschen eines Dateiobjekts die Datei schließt, aber ich kann nichts in der Dokumentation finden. – EOL

+5

Mein Verständnis ist, dass CPython (die Referenzimplementierung, an die die meisten Leute denken, wenn sie Python denken) in der Tat alle nicht referenzierten Objekte zerstört, wenn sie den Bereich verlassen. In diesem Fall verlässt das Dateiobjekt den Gültigkeitsbereich, sobald die Operation read() abgeschlossen ist. Also sollte es genau das tun, was du willst. Das ist jedoch kein garantiertes Verhalten. Andere Implementierungen von Python (ich glaube, Jython ist ein Paradebeispiel) können die Garbage Collection anders handhaben. Mein Instinkt besteht darin, die einfache Implementierung zu verwenden, wenn Sie wissen, dass Sie CPython verwenden und sich nicht um Portabilität kümmern. –

1

sieht gut aus mir .. Ich lese Dateien so oft.

6

Es ist wahr, dass es irgendwann schließen wird, aber vielleicht nicht bald genug. Vor allem, wenn Sie dies innerhalb einer Schleife verwenden, können dem System möglicherweise keine Dateihandles mehr zur Verfügung stehen, bevor der GC zu den Dateiobjekten gelangt.

+0

Oh, habe nie daran gedacht! – Claudiu

+0

Aber wenn die Dateiobj ist Referenz gezählt .. es geht direkt auf 0 und wird sofort gelöscht? In CPython (?). – u0b34a0f6ae

+0

@ kaizer.se: es ist immer noch nicht unbedingt sofort gelöscht. nur wenn CPython mehr Speicher benötigt. – Claudiu

4

Der Code funktioniert genau so, wie Sie sagen, es tut, aber es ist schlechter Stil dennoch. Ihr Code basiert auf Annahmen, die jetzt wahr sein können, aber nicht immer wahr sind. Es ist nicht unmöglich, dass Ihr Code in einer Situation ausgeführt wird, in der die geöffnete und nicht geschlossene Datei betrifft. Lohnt es sich wirklich, nur ein oder zwei Zeilen Code zu speichern? Ich denke nicht.

2

Auch wenn es wie erwartet funktioniert, ich denke, es ist in zweifacher Hinsicht versagt:

  1. Ihr Code wird nahtlos nicht vergrößern, da Sie die gesamte Datei in den Speicher lesen, und dies kann oder nicht sein unbedingt was du willst.
  2. Nach dem Zen von Python (versuchen Sie import this in der Python-Eingabeaufforderung, um es abzurufen) "Explizit ist besser als implizit", und indem Sie die Datei nicht explizit schließen, könnten Sie jemanden verwechseln, der die Straße verlassen wird mit Ihrem Code für die Wartung.

Es hilft wirklich, explizit zu sein! Python regt expliziten Stil an.

Abgesehen davon ist Ihr Stil für ein Wegwerf-Skript sinnvoll.

Vielleicht profitieren Sie von this answer.

Verwandte Themen