Wir können eine Liste einfach und direkt durch Listengenerierung erstellen, aber aufgrund von Speicherbeschränkungen ist die Listenkapazität definitiv begrenzt. Darüber hinaus nimmt die Erstellung einer Liste mit 1 Million Elementen nicht nur viel Speicherplatz in Anspruch, sondern wenn wir nur auf die ersten paar Elemente zugreifen müssen, wird der von den meisten nachfolgenden Elementen belegte Platz verschwendet.
Wenn also die Listenelemente nach einem bestimmten Algorithmus berechnet werden können, können wir dann während der Schleife kontinuierlich nachfolgende Elemente berechnen? Dadurch entfällt die Notwendigkeit, eine vollständige Liste zu erstellen, was viel Platz spart. In Python wird dieser Mechanismus zum gleichzeitigen Schleifen und Berechnen als Generator bezeichnet.
Es gibt viele Möglichkeiten, einen Generator zu erstellen. Die erste Methode ist sehr einfach. Ändern Sie einfach [] in () in einem Listengenerierungsausdruck, um einen Generator zu erstellen:
>>> mylist = [ x for x in range(1, 10)] >>> mylist [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> gen = (x for x in range(1,10)) >>> gen <generator object <genexpr> at 0x7f1d7fd0f5a0>
Create mylist Der einzige Unterschied from gen ist das äußerste [] und () ist eine Liste und gen ist ein Generator.
Wir können jedes Element der Liste direkt ausdrucken, aber wie drucken wir jedes Element des Generators aus?
Wenn Sie sie einzeln ausdrucken möchten, können Sie die next()-Methode des Generators verwenden:
>>> gen.next() 1 >>> gen.next() 2 >>> gen.next() 3 ... >>> gen.next() 9 >>> gen.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
Wie gesagt, der Generator speichert. Bei jedem Aufruf von next() wird der Wert des nächsten Elements berechnet, bis das letzte Element berechnet wird. Wenn keine weiteren Elemente vorhanden sind, wird ein StopIteration-Fehler ausgegeben.
Tatsächlich können wir die for-Schleife anstelle der next()-Methode verwenden, was eher den Ideen einer effizienten Programmierung entspricht:
>>> gen = ( x for x in range(1, 10)) >>> for num in gen: ... print num ... 1 2 3 4 5 6 7 8 9
Generator ist sehr leistungsstark. Wenn der Berechnungsalgorithmus relativ komplex ist und nicht über eine for-Schleife ähnlich der Listengenerierung implementiert werden kann, kann er auch über eine Funktion implementiert werden.
Zum Beispiel kann in der berühmten Fibonacci-Folge mit Ausnahme der ersten und zweiten Zahl jede beliebige Zahl zu den ersten beiden Zahlen hinzugefügt werden. Erhalten Sie:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
Die Fibonacci-Folge kann nicht mithilfe der Listengenerierung geschrieben werden, aber es ist einfach, sie mithilfe einer Funktion auszudrucken:
def fib(max): n = 0 a, b = 0, 1 while n < max: print b a, b = b, a + b n = n + 1
Die obige Funktion kann die ersten N Zahlen der Fibonacci-Folge ausgeben:
>>> fib(6) 1 1 2 3 5 8
Wenn Sie genau hinschauen, Sie Sie können sehen, dass die Fib-Funktion tatsächlich die Berechnungsregeln der Fibonacci-Folge definiert. Sie können mit dem ersten Element beginnen und alle nachfolgenden Elemente berechnen.
Mit anderen Worten, die obige Funktion ist nur einen Schritt vom Generator entfernt. Um die fib-Funktion in einen Generator umzuwandeln, ändern Sie einfach print b in yield b:
def fib(max): n = 0 a, b = 0, 1 while n < max: yield b a, b = b, a + b n = n + 1
Dies ist eine weitere Möglichkeit, eine Generatormethode zu definieren. Wenn eine Funktionsdefinition das Schlüsselwort yield enthält, ist die Funktion keine gewöhnliche Funktion mehr, sondern ein Generator:
>>> fib(6) <generator object fib at 0x104feaaa0>
Hier das letzte Was ist Schwer zu verstehen ist, dass der Ausführungsablauf von Generatoren und Funktionen unterschiedlich ist. Funktionen werden nacheinander ausgeführt und kehren zurück, wenn sie auf eine Return-Anweisung oder die letzte Zeile von Funktionsanweisungen stoßen. Die Funktion, die zum Generator wird, wird jedes Mal ausgeführt, wenn next() aufgerufen wird, kehrt zurück, wenn eine Yield-Anweisung auftritt, und setzt die Ausführung ab der Yield-Anweisung fort, die beim letzten Mal zurückgegeben wurde, wenn sie erneut ausgeführt wird.
Definieren Sie als einfaches Beispiel einen Generator, der die Zahlen 1, 3 und 5 nacheinander zurückgibt:
>>> def odd(): ... print 'step 1' ... yield 1 ... print 'step 2' ... yield 3 ... print 'step 3' ... yield 5 ... >>> o = odd() >>> o.next() step 1 1 >>> o.next() step 2 3 >>> o.next() step 3 5 >>> o.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
Wie Sie sehen können, ist odd keine gewöhnliche Funktion, sondern ein Generator. Während der Ausführung wird sie unterbrochen, wenn sie auf Yield stößt, und die Ausführung wird beim nächsten Mal fortgesetzt. Nachdem yield dreimal ausgeführt wurde, ist kein yield mehr auszuführen, daher wird beim vierten Aufruf von next() ein Fehler gemeldet.
Zurück zum Beispiel von Fib: Wenn wir während der Schleife weiterhin yield aufrufen, wird sie weiterhin unterbrochen. Natürlich müssen Sie eine Bedingung festlegen, damit die Schleife die Schleife verlässt, andernfalls wird eine unendliche Zahl aufgelistet.
In ähnlicher Weise verwenden wir nach dem Ändern der Funktion in einen Generator grundsätzlich nie next() zum Aufrufen, sondern verwenden direkt die for-Schleife zum Iterieren:
>>> for n in fib(6): ... print n ... 1 1 2 3 5 8
Generator ist ein sehr leistungsfähiges Werkzeug. In Python können Sie die Listengenerierung einfach in einen Generator umwandeln oder auch komplexe Logikgeneratoren über Funktionen implementieren.
Um das Funktionsprinzip des Generators zu verstehen, berechnet er während der for-Schleife kontinuierlich das nächste Element und beendet die for-Schleife unter geeigneten Bedingungen. Wenn bei einem von einer Funktion geänderten Generator die Return-Anweisung auftritt oder die letzte Zeile des Funktionskörpers ausgeführt wird, ist dies die Anweisung zum Beenden des Generators, und die for-Schleife endet entsprechend.