4

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?

+2

Wenn Sie zuerst 'open = print' aufrufen, dann wird der Code' a_file' gedruckt. –

+0

@StefanPochmann Es hat eine Weile gedauert, aber zumindest habe ich deinen Kommentar verstanden ... Vielen Dank – gboffi

+0

@MSeifert Sehr nette Bearbeitung! – gboffi

Antwort

4

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 in foo() , der eine Ausnahme auslöst, und einen Fehler in sum(), 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 in sum() eher die eine in foo() angehoben, da der Aufruf an foo() Teil des Arguments sum() ist, und ich erwarte, dass Argumente verarbeitet werden, bevor die Funktion aufgerufen wird.

OTOH, in sum(bar(x) for x in foo()), wo sum() und foo() bugfree sind, aber bar() eine Ausnahme auslöst, haben wir keine andere Wahl, als der Anruf an bar() bis sum() beginnt Iterieren zu verzögern - das ist ein Teil des Vertrag Generatoren. (Sie tun nichts, bis ihre next() Methode zuerst genannt.)

Sehen Sie den Rest dieses Abschnitts für die weitere Diskussion.

5

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. 
+0

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

1

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.