Wenn ich schreiben:Generatoren und Dateien
lines = (line.strip() for line in open('a_file'))
Ist die Datei sofort geöffnet oder ist das Dateisystem nur zugegriffen, wenn ich zu verbrauchen des Generator Ausdruck starten?
Wenn ich schreiben:Generatoren und Dateien
lines = (line.strip() for line in open('a_file'))
Ist die Datei sofort geöffnet oder ist das Dateisystem nur zugegriffen, wenn ich zu verbrauchen des Generator Ausdruck starten?
open()
wird sofort beim Bau des Generators aufgerufen, unabhängig davon, wann oder ob Sie davon konsumieren.
Die entsprechende Spezifikation ist PEP-289:
Früh im Vergleich zu später Bindung Bindung
Nach vielen Diskussionen war es entschieden, dass die erste (äußerste) für Expression sollte sofort ausgewertet werden und dass die restlichen Ausdrücke ausgewertet werden, wenn der Generator ausgeführt wird.
Fragte die Argumentation für die Bindung des ersten Ausdrucks zusammenzufassen, bot Guido [5]:
sum(x for x in foo())
Betrachten. Nun nehmen wir an, es gibt einen Fehler infoo()
, der eine Ausnahme auslöst, und einen Fehler insum()
, der eine Ausnahme auslöst, bevor es beginnt, über sein Argument zu iterieren. Welche Ausnahme würde Sie erwarten zu sehen? Ich wäre überrascht, wenn das insum()
eher die eine infoo()
angehoben, da der Aufruf anfoo()
Teil des Argumentssum()
ist, und ich erwarte, dass Argumente verarbeitet werden, bevor die Funktion aufgerufen wird.OTOH, in
sum(bar(x) for x in foo())
, wosum()
undfoo()
bugfree sind, aberbar()
eine Ausnahme auslöst, haben wir keine andere Wahl, als der Anruf anbar()
bissum()
beginnt Iterieren zu verzögern - das ist ein Teil des Vertrag Generatoren. (Sie tun nichts, bis ihrenext()
Methode zuerst genannt.)
Sehen Sie den Rest dieses Abschnitts für die weitere Diskussion.
Es ist sofort geöffnet. Sie können dies überprüfen, wenn Sie einen Dateinamen verwenden, der nicht vorhanden ist (es wird eine Ausnahme ausgelöst, die anzeigt, dass Python tatsächlich versucht hat, sie sofort zu öffnen).
Sie können auch eine Funktion verwenden, die mehr Feedback zu sehen gibt, dass der Befehl selbst ausgeführt wird, bevor der Generator über iteriert:
def somefunction(filename):
print(filename)
return open(filename)
lines = (line.strip() for line in somefunction('a_file')) # prints
jedoch, wenn Sie eine Generatorfunktion anstelle eines Generators Ausdruck verwenden, die Datei wird nur geöffnet, wenn Sie darüber iterieren:
def somefunction(filename):
print(filename)
for line in open(filename):
yield line.strip()
lines = somefunction('a_file') # no print!
list(lines) # prints because list iterates over the generator function.
Ich schätze Ihre Beobachtung über den Unterschied zwischen Generatorausdrücken und Generatorfunktionen. Ich habe deine Antwort nicht genehmigt, weil ich [die eine] (https://stackoverflow.com/a/45758642/2749397) bevorzuge, die auf den ursprünglichen Entscheidungsprozess verweist, aber deine ist eine sehr gute! – gboffi
Es wird sofort geöffnet.
Beispiel:
def func():
print('x')
return [1, 2, 3]
g = (x for x in func())
Output:
x
Die Funktion eines iterable Objekt zurückgeben muss. open()
gibt ein offenes Dateiobjekt zurück, das iterierbar ist. Daher wird die Datei geöffnet, wenn Sie den Generatorausdruck definieren.
Wenn Sie zuerst 'open = print' aufrufen, dann wird der Code' a_file' gedruckt. –
@StefanPochmann Es hat eine Weile gedauert, aber zumindest habe ich deinen Kommentar verstanden ... Vielen Dank – gboffi
@MSeifert Sehr nette Bearbeitung! – gboffi