Wie genau funktioniert ein Generatorverständnis?


90

Was macht das Generatorverständnis? Wie funktioniert es? Ich konnte kein Tutorial dazu finden.


1
Um klar zu sein, sind die Sprache Namen für diesen Generator Ausdrücke , nicht Generator Comprehensions .
ShadowRanger

1
@ShadowRanger Im Juli 2018 wurde auf der Python-dev-Mailingliste eine Diskussion über die "Syntax des Namensverständnisses " geführt, bei der vorläufige, aber ziemlich einstimmige Übereinstimmung bestand, sie aus Gründen der Konsistenz als "Generatorverständnis" zu bezeichnen.
Aaron Hall

Antworten:


143

Verstehst du Listenverständnis? Wenn ja, ist ein Generatorausdruck wie ein Listenverständnis, aber anstatt alle gewünschten Elemente zu finden und in eine Liste zu packen, wartet er und gibt jedes Element einzeln aus dem Ausdruck heraus.

>>> my_list = [1, 3, 5, 9, 2, 6]
>>> filtered_list = [item for item in my_list if item > 3]
>>> print(filtered_list)
[5, 9, 6]
>>> len(filtered_list)
3
>>> # compare to generator expression
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> print(filtered_gen)  # notice it's a generator object
<generator object <genexpr> at 0x7f2ad75f89e0>
>>> len(filtered_gen) # So technically, it has no length
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> # We extract each item out individually. We'll do it manually first.
... 
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # Should be all out of items and give an error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # Yup, the generator is spent. No values for you!
... 
>>> # Let's prove it gives the same results as our list comprehension
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> gen_to_list = list(filtered_gen)
>>> print(gen_to_list)
[5, 9, 6]
>>> filtered_list == gen_to_list
True
>>> 

Da ein Generatorausdruck jeweils nur ein Element liefern muss, kann dies zu erheblichen Einsparungen bei der Speichernutzung führen. Generatorausdrücke sind in Szenarien am sinnvollsten, in denen Sie jeweils ein Element aufnehmen, viele Berechnungen basierend auf diesem Element durchführen und dann mit dem nächsten Element fortfahren müssen. Wenn Sie mehr als einen Wert benötigen, können Sie auch einen Generatorausdruck verwenden und jeweils mehrere Werte abrufen. Wenn Sie alle Werte benötigen, bevor Ihr Programm fortgesetzt wird, verwenden Sie stattdessen ein Listenverständnis.


3
Eine Frage hier. Ich habe next (gen_name) verwendet, um das Ergebnis zu erhalten, und es hat in Python 3 funktioniert. Gibt es ein bestimmtes Szenario, in dem wir __next __ () verwenden müssen?
Ankit Vashistha

2
@ AnkitVashistha Nein, immer next(...)anstelle von .__next__()in Python 3 verwenden.
Todd Sewell

@gotgenes @AnkitVashistha If you need more than one value, you can also use a generator expression and grab a few at a time. Könnten Sie bitte ein Beispiel für diese Verwendung geben? Vielen Dank.
LittleZero

19

Ein Generatorverständnis ist die träge Version eines Listenverständnisses.

Es ist wie ein Listenverständnis, nur dass es anstelle der Liste einen Iterator zurückgibt, dh ein Objekt mit einer next () -Methode, das das nächste Element liefert.

Wenn Sie mit Listenverständnissen nicht vertraut sind, finden Sie hier und für Generatoren hier .


4

Das Listen- / Generatorverständnis ist ein Konstrukt, mit dem Sie eine neue Liste / einen neuen Generator aus einer vorhandenen erstellen können.

Angenommen, Sie möchten die Liste der Quadrate jeder Zahl von 1 bis 10 generieren. Sie können dies in Python tun:

>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Hier range(1,11)wird die Liste generiert [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], aber die rangeFunktion ist kein Generator vor Python 3.0, und daher ist das Konstrukt, das ich verwendet habe, ein Listenverständnis.

Wenn ich einen Generator erstellen wollte, der dasselbe tut, könnte ich das so machen:

>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>

In Python 3 handelt es sich jedoch rangeum einen Generator, sodass das Ergebnis nur von der verwendeten Syntax abhängt (eckige Klammern oder runde Klammern).


4
Das ist falsch. Ob der äußere Ausdruck ein Generator ist, hat nichts damit zu tun, ob der innere Ausdruck ist. Obwohl es normalerweise nicht sinnvoll ist, in einem Generatorausdruck Elemente aus einer Liste zu übernehmen, können Sie dies tun.
Antimon

Kann dies deutlicher umgeschrieben werden? Ich verstehe, was Sie sagen, aber wie Antimon sagt, sieht es so aus, als würden Sie etwas anderes sagen. (und das, was Sie sagen, ist falsch)
Lyndon White

3

Das Generatorverständnis ist eine einfache Möglichkeit, Generatoren mit einer bestimmten Struktur zu erstellen. Nehmen wir an, Sie möchten eine generator, die nacheinander alle geraden Zahlen ausgibt your_list. Wenn Sie es mit dem Funktionsstil erstellen, sieht es folgendermaßen aus:

def allEvens( L ):
    for number in L:
        if number % 2 is 0:
            yield number

evens = allEvens( yourList )

Mit diesem Generatorverständnisausdruck können Sie dasselbe Ergebnis erzielen:

evens = ( number for number in your_list if number % 2 == 0 )

In beiden Fällen erhalten Sie beim Anruf next(evens)die nächste gerade Nummer your_list.


0

Das Generatorverständnis ist ein Ansatz zum Erstellen von Iterables, ähnlich einem Cursor, der sich auf einer Ressource bewegt. Wenn Sie den MySQL-Cursor oder den Mongodb-Cursor kennen, wissen Sie möglicherweise, dass die gesamten tatsächlichen Daten nie auf einmal, sondern einzeln in den Speicher geladen werden. Ihr Cursor bewegt sich hin und her, aber es befindet sich immer ein Element mit einer Zeile / Liste im Speicher.

Kurz gesagt, mithilfe des Generatorverständnisses können Sie problemlos Cursor in Python erstellen.


-1

Ein weiteres Beispiel für das Verständnis des Generators:

print 'Generator comprehensions'

def sq_num(n):
    for num in (x**2 for x in range(n)):    
        yield num

for x in sq_num(10):
    print x 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.