Öffnen Sie das Lesen und Schließen einer Datei in einer Codezeile

127

Jetzt benutze ich:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Aber damit der Code besser aussieht, kann ich Folgendes tun:

output = open('pagehead.section.htm','r').read()

Wie schließe ich die Datei bei Verwendung der obigen Syntax, um Systemressourcen freizugeben?

1qazxsw2
quelle
19
Einzeiler sind von Natur aus nicht attraktiver. Code wird viel häufiger gelesen als geschrieben und sollte zum Verständnis geschrieben werden, nicht aus Gründen der "Coolness". Die einzige Ausnahme ist, wenn es eine bekannte Sprache in einer Sprache gibt, aber mir ist in diesem Fall keine bekannt.
Drdwilcox
17
@drdwilcox: Kryptische Einzeiler sind schlecht, deklarative Einzeiler sind gut. Es gibt keinen Grund (zumindest kann ich keinen sehen), warum es im Kern keinen Funktions-Wrapper gibt, um eine Datei (so häufig erforderlich) in einem einzigen Funktionsaufruf zu lesen. So etwas wie contents = os.readfile(path). Wenn ich etwas schickeres machen wollte, dann würde ich es gerne benutzen with open(path) as fd: contents = fd.read(). Natürlich kann man einen eigenen Wrapper schreiben, aber dafür ist der Kern gedacht, um Programmierern Abstraktionen zu bieten.
Tokland
5
Es ist wahr, dass Code viel mehr gelesen als geschrieben wird, aber die Implikation, dass längerer Code genauso gut ist wie kurzer Code, könnte nicht falscher sein. Wenn Sie Zeit investieren, um Ihren Code so kurz wie möglich zu halten (ohne auf clevere Tricks zurückzugreifen, die schwer zu verstehen sind), zahlt sich diese Investition beim Lesen des Codes immer wieder aus. Jede Zeile, die Sie schreiben, ist für jeden, der Ihren Code liest, ein schlechter Dienst. Sie sollten sich daher bemühen, so wenig wie möglich zu schreiben. Erinnern Sie sich an das berühmte Zitat von Pascal: "Ich habe diesen Brief nur länger gemacht, weil ich nicht die Muße hatte, ihn kürzer zu machen."
John Williams

Antworten:

194

Sie müssen es nicht wirklich schließen - Python erledigt dies automatisch entweder während der Speicherbereinigung oder beim Beenden des Programms. Aber wie @delnan bemerkte, ist es aus verschiedenen Gründen besser, es explizit zu schließen.

Was können Sie also tun, um es kurz, einfach und explizit zu halten:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Jetzt sind es nur noch zwei Zeilen und ziemlich lesbar, denke ich.

Tim Pietzcker
quelle
2
@ 1qazxsw2 Wenn Sie die withAnweisung verwenden, wird die Dateiressource für Sie ordnungsgemäß geschlossen.
David Alber
13
Zum ersten Satz: Python wird ihn irgendwann schließen . Das heißt aber nicht, dass Sie das Schließen vergessen sollten. Selbst beim Nachzählen bleibt die Datei möglicherweise viel länger geöffnet, als Sie denken und wollen (z. B. wenn zufällig auf Zyklen verwiesen wird). Dies gilt dreimal für Python-Implementierungen mit einem anständigen GC, bei denen Sie nicht garantieren können, dass zu einem bestimmten Zeitpunkt etwas GC-fähig ist. Selbst in der CPython-Dokumentation heißt es, dass Sie sich bei einer solchen Bereinigung nicht auf GC verlassen sollten. Der letzte Teil der Antwort sollte fett sein.
6
Wenn Sie wirklich eine benötigen Einzeiler , ist es möglich , die setzen output = f.read()Teil auf der gleichen Linie , nachdem der :.
Karl Knechtel
1
"Öffnen, Lesen und Schließen einer Datei in einer Codezeile" Dies sind zwei Zeilen, die die Frage nicht beantworten.
user5359531
1
Das hängt von der Implementierung ab - siehe Svens Antwort.
Tim Pietzcker
71

Das Python Standard Library Pathlib- Modul macht das, wonach Sie suchen:

Path('pagehead.section.htm').read_text()

Vergessen Sie nicht, Path zu importieren:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

Installieren Sie auf Python 27 backported pathliboderpathlib2

Janusz Skonieczny
quelle
8
Die anderen vorgeschlagenen Antworten withsind in Ordnung, aber witheine Aussage, kein Ausdruck. Diese pathlibAntwort ist die einzige Antwort auf die ursprüngliche Frage, die in einen Python-Ausdruck eingebettet werden kann. So etwas wieSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

Mit CPython wird Ihre Datei sofort nach Ausführung der Zeile geschlossen, da das Dateiobjekt sofort durch Müll gesammelt wird. Es gibt jedoch zwei Nachteile:

  1. In Python-Implementierungen, die sich von CPython unterscheiden, wird die Datei häufig nicht sofort geschlossen, sondern zu einem späteren Zeitpunkt außerhalb Ihrer Kontrolle.

  2. In Python 3.2 oder höher wird ein ResourceWarning, wenn aktiviert, ausgelöst.

Besser eine zusätzliche Zeile investieren:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Dadurch wird sichergestellt, dass die Datei unter allen Umständen korrekt geschlossen wird.

Sven Marnach
quelle
17

Dazu müssen keine speziellen Bibliotheken importiert werden.

Verwenden Sie die normale Syntax und die Datei wird zum Lesen geöffnet und dann geschlossen.

with open("/etc/hostname","r") as f: print f.read() 

oder

with open("/etc/hosts","r") as f: x = f.read().splitlines()

Dies gibt Ihnen ein Array x, das die Zeilen enthält und wie folgt gedruckt werden kann:

for line in x: print line

Diese Einzeiler sind sehr hilfreich für die Wartung - im Grunde genommen selbstdokumentierend.

SDsolar
quelle
8

Sie können die withAnweisung verwenden und die beiden Schritte in eine Zeile schreiben:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

Die withAnweisung achtet darauf, die __exit__Funktion des angegebenen Objekts aufzurufen, auch wenn in Ihrem Code etwas Schlimmes passiert ist. Es ist nah an der try... finallySyntax. Für Objekt zurückgegeben durch open, __exit__entspricht Datei Schließung.

Diese Anweisung wurde mit Python 2.6 eingeführt.

Joël
quelle
Kleine Klarstellung: nach der Dokumentation with wurde in Python 2.5, eingeführt aber werden mußte explizit importiert aus __future__. Es wurde in Python 2.6 aus allen Kontexten verfügbar.
David Alber
5

benutze ilio : (inline io):

Nur ein Funktionsaufruf anstelle der Datei open (), read (), close ().

from ilio import read

content = read('filename')
Iman
quelle
2
with open('pagehead.section.htm')as f:contents=f.read()

quelle
4
Wie unterscheidet sich das von den Top 3 Antworten?
Alle Arbeiter sind essentiell
4
Der größte Unterschied besteht darin, dass es sich bei der angegebenen Frage nur um eine Zeile handelt. Persönlich kann ich darüber hinaus nichts finden, aber ich kann meine Arbeit gerne kritisieren, anstatt selbst einen Beitrag zur Frage zu leisten.
3
Die kürzeste integrierte Methode zum Öffnen, Lesen und Schließen einer Datei in Python besteht darin, zwei logische Zeilen zu verwenden, unabhängig davon, ob sie auf eine Zeile komprimiert sind oder nicht. Ich sehe diese Antwort also nicht als effektiv anders als die 3 ursprünglichen Antworten.
Alle Arbeiter sind essentiell
1
Es spielt keine Rolle, ob es "effektiv" anders ist. Ich bin auf diese Seite gekommen und habe nach einer einzeiligen Syntax gesucht, die python -cin der Befehlszeile verwendet werden kann. Daher hilft es nicht, zweizeilige Antworten zu veröffentlichen.
user5359531
1
@ user5359531 Ich verstehe Ihren Standpunkt nicht: Wissen Sie, dass Sie Python-Ausdrücke mit zitieren ", ;zwei Anweisungen anhängen und danach Zeilenumbrüche löschen können :? Der folgende Ausdruck funktioniert gut für mich:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël
2

Ich denke, der natürlichste Weg, dies zu erreichen, besteht darin, eine Funktion zu definieren.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Dann können Sie Folgendes tun:

output = read('pagehead.section.htm')
Adrien Pavao
quelle
0

Ich mache häufig so etwas, wenn ich ein paar Zeilen um etwas bekommen muss, das ich in einer Protokolldatei erfasst habe:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Matthew Purdon
quelle
1
Völlig unabhängig von dem ursprünglichen Thema, aber Sie sollten in schauen grep -A <n>, grep -B <n>und grep -C <n>, wenn es nützlich ist. Weitere Informationen: stackoverflow.com/a/9083/1830159
Liam Stanley
0

Mit more_itertools.with_iterkönnen Sie ein Äquivalent outputin einer Zeile öffnen, lesen, schließen und zuweisen (ohne die Importanweisung):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Obwohl dies möglich ist, würde ich nach einem anderen Ansatz suchen als dem Zuweisen des Inhalts einer Datei zu einer Variablen, dh einer verzögerten Iteration. Dies kann mithilfe eines herkömmlichen withBlocks oder im obigen Beispiel durch Entfernen join()und Iterieren erfolgen output.

Pylang
quelle
Sie können auch in den Oneliner importieren. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Dies funktioniert einwandfrei und macht eine Zeile für den Import überflüssig.
Melwil
1
Ich stimme völlig mit Ihnen. Während ich mit Onelinern über das Lösen von Aufgaben diskutierte, fand ich mich oft in Argumenten wieder, in denen das vereinbarte Ergebnis eine einzelne Codezeile sein sollte, die in eine neue Python-Shell eingefügt wurde. Solche Herausforderungen entsprechen selten pep8. Es ist in keiner Weise eine gute Praxis zum Schreiben von Code, es war nur als Tipp gedacht, um die Notwendigkeit von Importen zu beseitigen.
Melwil
0

Wenn Sie dieses warme und verschwommene Gefühl wollen, gehen Sie einfach mit .

Für Python 3.6 habe ich diese beiden Programme unter einem Neuanfang von IDLE ausgeführt und dabei folgende Laufzeiten angegeben:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Also kein großer Unterschied.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

AUSGABE:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

AUSGABE:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
quelle