Der wichtige Punkt ist, dass die Liste Verständnis eine neue Liste erstellt. Der Generator erzeugt ein iterierbares Objekt, das das Quellmaterial während des Verbrauchs der Bits "filtert".
Stellen Sie sich vor, Sie haben eine 2TB-Protokolldatei namens "rianglefile.txt", und Sie möchten den Inhalt und die Länge für alle Zeilen, die mit dem Wort "ENTRY" beginnen.
Also versuchen Sie durch das Schreiben einer Liste Verständnis anfangen:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Diese schlürft die gesamte Datei auf, verarbeitet jede Zeile und speichert die passenden Zeilen in der Matrix. Dieses Array könnte daher bis zu 2 TB Inhalt enthalten. Das ist viel RAM und wahrscheinlich nicht praktisch für Ihre Zwecke.
Stattdessen können wir stattdessen einen Generator verwenden, um einen "Filter" auf unseren Inhalt anzuwenden. Es werden keine Daten gelesen, bis wir mit dem Iterieren des Ergebnisses beginnen.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Noch nicht einmal eine Zeile wurde aus unserer Datei gelesen. In der Tat, sagen wir unser Ergebnis weiter filtern möchten:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Immer noch nichts gelesen wurde, aber wir haben jetzt zwei Generatoren angegeben, die auf unsere Daten handeln, wie wir wollen.
Lets unsere gefilterten Linien auf eine andere Datei schreiben:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Jetzt wir die Eingabedatei lesen. Da unsere for
Schleife weiterhin zusätzliche Leitungen anfordert, fordert der long_entries
Generator Leitungen vom Generator entry_lines
an und gibt nur diejenigen zurück, deren Länge mehr als 80 Zeichen beträgt. Und wiederum fordert der Generator entry_lines
Zeilen an (gefiltert wie angezeigt) von dem logfile
Iterator, der wiederum die Datei liest.
Anstatt also Daten in Form einer vollständig ausgefüllten Liste an Ihre Ausgabefunktion zu "pushen", geben Sie der Ausgabefunktion eine Möglichkeit, Daten nur dann "abzuholen", wenn sie benötigt wird. Dies ist in unserem Fall viel effizienter, aber nicht ganz so flexibel. Generatoren sind ein Weg, ein Durchgang; Die Daten aus der Protokolldatei, die wir gelesen haben, werden sofort verworfen, sodass wir nicht zu einer vorherigen Zeile zurückkehren können. Auf der anderen Seite müssen wir uns nicht darum kümmern, Daten zu speichern, sobald wir damit fertig sind.
könnte '[exp für x in iter]' sei einfach Zucker für 'list ((exp für x in iter))'? oder gibt es einen Ausführungsunterschied? – b0fh
es denke, ich hatte eine relevante Frage, so dass bei der Verwendung von Ertrag können wir nur den Generator Ausdruck von einer Funktion verwenden, oder müssen wir Ausbeute für eine Funktion, um Generator-Objekt zurückgeben? –
@ b0fh Sehr späte Antwort auf Ihren Kommentar: In Python2 gibt es einen winzigen Unterschied, die Schleifenvariable wird aus einem Listenverständnis herauslecken, während ein Generatorausdruck nicht leckt. Vergleiche 'X = [x ** 2 für x im Bereich (5)]; drucke x' mit 'Y = Liste (y ** 2 für y im Bereich (5)); print y', der zweite gibt einen Fehler. In Python3 ist ein List-Verständnis in der Tat der syntaktische Zucker für einen Generator-Ausdruck, der 'list()' wie erwartet zugeführt wird, so dass die Loop-Variable nicht mehr ausläuft (https://www.python.org/dev/). peps/pep-0289 # the-details). –