Oft muss ich Daten entweder in eine Datei oder, wenn keine Datei angegeben ist, in stdout ausgeben. Ich benutze das folgende Snippet:
if target:
with open(target, 'w') as h:
h.write(content)
else:
sys.stdout.write(content)
Ich möchte es umschreiben und beide Ziele einheitlich behandeln.
Im Idealfall wäre es:
with open(target, 'w') as h:
h.write(content)
Dies funktioniert jedoch nicht gut, da sys.stdout beim Verlassen des with
Blocks geschlossen wird und ich das nicht möchte. Ich will auch nicht
stdout = open(target, 'w')
...
weil ich daran denken müsste, das ursprüngliche stdout wiederherzustellen.
Verbunden:
- Stdout in eine Datei in Python umleiten?
- Behandlung von Ausnahmen - interessanter Artikel über die Behandlung von Ausnahmen in Python im Vergleich zu C ++
Bearbeiten
Ich weiß, dass ich einschließen target
, separate Funktionen definieren oder den Kontextmanager verwenden kann . Ich suche eine einfache, elegante, idiomatische Lösung, die nicht mehr als 5 Zeilen benötigt
Antworten:
Wenn Sie hier nur über den Tellerrand hinaus denken, wie wäre es mit einer benutzerdefinierten
open()
Methode?Verwenden Sie es so:
quelle
Halten Sie sich an Ihren aktuellen Code. Es ist einfach und Sie können genau sagen , was es tut, indem Sie es sich ansehen.
Ein anderer Weg wäre mit einem Inline
if
:Aber das ist nicht viel kürzer als das, was Sie haben, und es sieht wohl schlimmer aus.
Sie könnten auch nicht
sys.stdout
verschließbar machen , aber das scheint nicht zu pythonisch:quelle
with unclosable(sys.stdout): ...
indem Siesys.stdout.close = lambda: None
in diesem Kontextmanager festlegen und ihn anschließend auf den alten Wert zurücksetzen. Aber das scheint ein bisschen zu weit hergeholt ...Warum LBYL, wenn Sie EAFP können?
Warum sollten Sie es umschreiben, um den
with
/as
block einheitlich zu verwenden, wenn Sie dafür sorgen müssen, dass er verschlungen funktioniert? Sie fügen mehr Zeilen hinzu und reduzieren die Leistung.quelle
for
Schleife beendet wird, indem ein StopIteration-Fehler abgefangen wird, der von dem Iterator ausgelöst wird, über den er sich schleift, würde ich sagen, dass die Verwendung von Ausnahmen für die Flusssteuerung absolut pythonisch ist.target
ist ,None
wenn sys.stdout vorgesehen ist, müssen Sie fangen ,TypeError
stattIOError
.Eine andere mögliche Lösung: Versuchen Sie nicht, die Exit-Methode des Kontextmanagers zu vermeiden, sondern duplizieren Sie stdout.
quelle
Eine Verbesserung von Wolphs Antwort
Dies ermöglicht binäre E / A und übergibt eventuelle irrelevante Argumente an
open
if , wennfilename
es sich tatsächlich um einen Dateinamen handelt.quelle
Ich würde mich auch für eine einfache Wrapper-Funktion entscheiden, die ziemlich einfach sein kann, wenn Sie den Modus (und folglich stdin vs. stdout) ignorieren können, zum Beispiel:
quelle
ValueError: I/O operation on closed file
wenn ich versuche, in die Datei außerhalb deswith open_or_stdout(..)
Blocks zu schreiben . Was vermisse ich? sys.stdout soll nicht geschlossen werden.Okay, wenn wir in Einzeilerkriege geraten, hier ist:
Ich mag Jacobs ursprüngliches Beispiel, solange der Kontext nur an einer Stelle geschrieben ist. Es wäre ein Problem, wenn Sie die Datei für viele Schreibvorgänge erneut öffnen würden. Ich denke, ich würde die Entscheidung nur einmal oben im Skript treffen und das System die Datei beim Beenden schließen lassen:
Sie können Ihren eigenen Exit-Handler einbinden, wenn Sie der Meinung sind, dass er ordentlicher ist
quelle
__del__
das tun würden.Wenn Sie wirklich auf etwas "Eleganterem" bestehen müssen, dh auf einem Einzeiler:
foo.txt
erscheint und enthält den Textfoo
.quelle
Wie wäre es mit einem neuen fd für sys.stdout? Auf diese Weise haben Sie keine Probleme beim Schließen:
quelle
./script.py >> file
Überschreiben der Datei entstehen, anstatt sie anzuhängen.In einigen Fällen leichte Verbesserung.
quelle
Nur zwei zusätzliche Zeilen, wenn Sie Python 3.3 oder höher verwenden: eine Zeile für die zusätzliche
import
und eine Zeile für diestack.enter_context
.quelle