Wann sollten Sie Generatorausdrücke verwenden und wann sollten Sie Listenverständnisse in Python verwenden?
# Generator expression
(x*2 for x in range(256))
# List comprehension
[x*2 for x in range(256)]
python
list-comprehension
generator
Schreibgeschützt
quelle
quelle
[exp for x in iter]
nur Zucker seinlist((exp for x in iter))
? oder gibt es einen Ausführungsunterschied?X = [x**2 for x in range(5)]; print x
mitY = list(y**2 for y in range(5)); print y
, die zweite gibt einen Fehler. In Python3 ist ein Listenverständnis in der Tat der syntaktische Zucker für einen Generatorausdruck, derlist()
wie erwartet eingespeist wird, sodass die Schleifenvariable nicht mehr ausläuft .Antworten:
Johns Antwort ist gut (das Listenverständnis ist besser, wenn Sie etwas mehrmals durchlaufen möchten). Es ist jedoch auch erwähnenswert, dass Sie eine Liste verwenden sollten, wenn Sie eine der Listenmethoden verwenden möchten. Der folgende Code funktioniert beispielsweise nicht:
Verwenden Sie grundsätzlich einen Generatorausdruck, wenn Sie nur einmal iterieren. Wenn Sie die generierten Ergebnisse speichern und verwenden möchten, sind Sie mit einem Listenverständnis wahrscheinlich besser dran.
Da Leistung der häufigste Grund ist, eine über die andere zu wählen, ist mein Rat, sich keine Sorgen zu machen und nur eine auszuwählen. Wenn Sie feststellen, dass Ihr Programm zu langsam läuft, sollten Sie sich nur dann Gedanken über die Optimierung Ihres Codes machen.
quelle
a = [1, 2, 3] b = [4, 5, 6] a.extend(b)
- a wird jetzt [1, 2, 3, 4, 5, 6] sein. (Können Sie Zeilenumbrüche in Kommentaren hinzufügen?)a = (x for x in range(0,10)), b = [1,2,3]
zum Beispiel.a.extend(b)
löst eine Ausnahme aus.b.extend(a)
wird alles auswerten, in diesem Fall macht es keinen Sinn, es überhaupt zu einem Generator zu machen.Das Iterieren über den Generatorausdruck oder das Listenverständnis bewirkt dasselbe. Das Listenverständnis erstellt jedoch zuerst die gesamte Liste im Speicher, während der Generatorausdruck die Elemente im laufenden Betrieb erstellt, sodass Sie sie für sehr große (und auch unendliche!) Sequenzen verwenden können.
quelle
itertools.count(n)
ist eine unendliche Folge von ganzen Zahlen, beginnend mit n, also(2 ** item for item in itertools.count(n))
eine unendliche Folge der Potenzen des2
Beginns bei2 ** n
.Verwenden Sie Listenverständnisse, wenn das Ergebnis mehrmals wiederholt werden muss oder wenn Geschwindigkeit an erster Stelle steht. Verwenden Sie Generatorausdrücke, bei denen der Bereich groß oder unendlich ist.
Weitere Informationen finden Sie unter Generatorausdrücke und Listenverständnisse .
quelle
lists
Sind sie also schneller alsgenerator
Ausdrücke? Beim Lesen der Antwort von dF stellte sich heraus, dass es umgekehrt war.Der wichtige Punkt ist, dass das Listenverständnis eine neue Liste erstellt. Der Generator erstellt ein iterierbares Objekt, das das Quellmaterial im laufenden Betrieb "filtert", während Sie die Bits verbrauchen.
Stellen Sie sich vor, Sie haben eine 2-TB-Protokolldatei mit dem Namen "vastfile.txt" und möchten den Inhalt und die Länge aller Zeilen, die mit dem Wort "ENTRY" beginnen.
Versuchen Sie also zunächst, ein Listenverständnis zu schreiben:
Dadurch wird die gesamte Datei verschluckt, jede Zeile verarbeitet und die übereinstimmenden Zeilen in Ihrem Array gespeichert. Dieses Array kann daher bis zu 2 TB Inhalt enthalten. Das ist viel RAM und wahrscheinlich nicht praktisch für Ihre Zwecke.
Stattdessen können wir einen Generator verwenden, um einen "Filter" auf unseren Inhalt anzuwenden. Es werden tatsächlich keine Daten gelesen, bis wir beginnen, über das Ergebnis zu iterieren.
Es wurde noch nicht einmal eine einzige Zeile aus unserer Datei gelesen. Nehmen wir an, wir möchten unser Ergebnis noch weiter filtern:
Es wurde noch nichts gelesen, aber wir haben jetzt zwei Generatoren angegeben, die auf unsere Daten reagieren, wie wir es wünschen.
Schreiben wir unsere gefilterten Zeilen in eine andere Datei:
Jetzt lesen wir die Eingabedatei. Da unsere
for
Schleife weiterhin zusätzliche Zeilen anfordert,long_entries
fordert der Generator Zeilen vomentry_lines
Generator an und gibt nur diejenigen zurück, deren Länge größer als 80 Zeichen ist. Derentry_lines
Generator fordert wiederum Zeilen (gefiltert wie angegeben) vomlogfile
Iterator an, der wiederum die Datei liest.Anstatt Daten in Form einer vollständig ausgefüllten Liste an Ihre Ausgabefunktion zu "pushen", geben Sie der Ausgabefunktion die Möglichkeit, Daten nur dann zu "ziehen", wenn sie benötigt werden. Dies ist in unserem Fall viel effizienter, aber nicht ganz so flexibel. Generatoren sind eine Möglichkeit, ein Durchgang; Die Daten aus der von uns gelesenen Protokolldatei werden sofort verworfen, sodass wir nicht zu einer vorherigen Zeile zurückkehren können. Auf der anderen Seite müssen wir uns keine Sorgen mehr machen, dass die Daten erhalten bleiben, wenn wir damit fertig sind.
quelle
Der Vorteil eines Generatorausdrucks besteht darin, dass er weniger Speicher benötigt, da nicht die gesamte Liste auf einmal erstellt wird. Generatorausdrücke werden am besten verwendet, wenn die Liste ein Vermittler ist, z. B. das Summieren der Ergebnisse oder das Erstellen eines Diktats aus den Ergebnissen.
Zum Beispiel:
Der Vorteil besteht darin, dass die Liste nicht vollständig generiert wird und daher wenig Speicher verwendet wird (und auch schneller sein sollte).
Sie sollten jedoch Listenverständnisse verwenden, wenn das gewünschte Endprodukt eine Liste ist. Sie werden keine Speicher mit Generatorausdrücken speichern, da Sie die generierte Liste möchten. Sie haben auch den Vorteil, dass Sie alle Listenfunktionen wie sortiert oder umgekehrt verwenden können.
Zum Beispiel:
quelle
sum(x*2 for x in xrange(256))
sorted
undreversed
funktionieren gut mit allen iterierbaren Generatorausdrücken.Beachten Sie beim Erstellen eines Generators aus einem veränderlichen Objekt (wie einer Liste), dass der Generator zum Zeitpunkt der Verwendung des Generators und nicht zum Zeitpunkt der Erstellung des Generators nach dem Status der Liste bewertet wird:
Wenn die Möglichkeit besteht, dass Ihre Liste geändert wird (oder ein veränderbares Objekt in dieser Liste), Sie jedoch den Status bei der Erstellung des Generators benötigen, müssen Sie stattdessen ein Listenverständnis verwenden.
quelle
Manchmal kann man mit der Tee- Funktion von itertools davonkommen . Sie gibt mehrere Iteratoren für denselben Generator zurück, die unabhängig voneinander verwendet werden können.
quelle
Ich verwende das Hadoop Mincemeat-Modul . Ich denke, dies ist ein großartiges Beispiel, um Folgendes zur Kenntnis zu nehmen:
Hier holt der Generator Zahlen aus einer Textdatei (bis zu 15 GB) und wendet einfache Berechnungen mit Hadoops Kartenreduzierung auf diese Zahlen an. Wenn ich nicht die Ertragsfunktion verwendet hätte, sondern ein Listenverständnis, hätte die Berechnung der Summen und des Durchschnitts viel länger gedauert (ganz zu schweigen von der Raumkomplexität).
Hadoop ist ein gutes Beispiel für die Nutzung aller Vorteile von Generatoren.
quelle