Lassen Sie uns Pythons Iterator und Generator zusammenfassen.
(Ergänzung 2018.12.25: Vollständig durch Python 3-Grammatik ersetzt)
--Iterator: Eine Schnittstelle, über die Sie Elemente iterativ abrufen können (https://docs.python.org/2/library/stdtypes.html#iterator-types). --Generator: Ein Iteratortyp, der jedes Element verarbeitet, wenn es versucht, es abzurufen, und das Element generiert. In Python scheint es, dass es sich häufig auf die Implementierung bezieht, die die Yield-Anweisung verwendet.
Jede in Python integrierte Sammlung (Liste, Tupel, Menge, Diktat usw.) kann iteriert werden. Für die iterative Verarbeitung mit der integrierten Sammlung muss die Sammlung jedoch im Voraus ausgefüllt werden. In den folgenden Fällen: Ich denke, es gibt Fälle, in denen Sie einen Iterator oder Generator selbst implementieren möchten.
Wenn Sie ein Objekt in einen Kontext einfügen, der einen Iterator erwartet, z. B. "for" in, wird zuerst die Methode "iter ()" des Objekts aufgerufen, sodass eine Iterator-Implementierung zurückgegeben werden muss. Das durch diesen Rückgabewert erhaltene Objekt wird als Methode next () bezeichnet. next () wird aufgerufen, bis Sie eine StopIteration-Ausnahme erhalten.
Es unterscheidet sich nicht von der normalen Liste, ist jedoch ein Beispiel für eine Implementierung, die eine Liste von Zahlen zurückgibt, die zum Zeitpunkt der Instanziierung in der angegebenen Reihenfolge angegeben wurden.
sample1.py
class MyIterator(object):
def __init__(self, *numbers):
self._numbers = numbers
self._i = 0
def __iter__(self):
# __next__()Wird von self implementiert, gibt es self so zurück, wie es ist
return self
def __next__(self): #Weiter für Python2(self)Definiert in
if self._i == len(self._numbers):
raise StopIteration()
value = self._numbers[self._i]
self._i += 1
return value
my_iterator = MyIterator(10, 20, 30)
for num in my_iterator:
print('hello %d' % num)
Ergebnis ist
hello 10 hello 20 hello 30
Wird sein.
In diesem Beispiel gibt __iter__ ()
self zurück. Wenn die Verarbeitung für die Iteration jedoch wahrscheinlich kompliziert wird, implementieren Sie eine Implementierungsklasse für die Iteration separat und generieren Sie ein solches Objekt. Es ist auch möglich, es zurückzugeben.
Wenn Sie die integrierte Funktion iter ()
verwenden, können Sie sehen, dass integrierte Typen wie list ebenfalls nach dieser Regel implementiert werden.
>>> hoge = [1, 2, 3]
>>> hoge_iter = iter(hoge)
>>> hoge_iter.__next__()
1
>>> hoge_iter.__next__()
2
>>> hoge_iter.__next__()
3
>>> hoge_iter.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
__next__ ()
gibt bei jedem Aufruf einen neuen Wert zurückEs mag schwierig sein, den Ertrag zu verstehen, wenn Sie nicht daran gewöhnt sind, aber der Mechanismus ist einfach. Es ist nicht erforderlich, eine Klasse zu definieren, wenn ein Generator mit Yield implementiert wird. Definieren wir die folgende Generatorfunktion.
my_generator.py
def my_generator():
yield 1
yield 2
yield 3
Dies ist ein Generator, der nacheinander drei Werte generiert: "1", "2" und "3". Beachten Sie, dass ** return-Anweisungen nicht in Generatorfunktionen ** verwendet werden können.
Generatoren werden häufig in den folgenden Fällen verwendet, in denen Rechenkosten ein Problem darstellen.
--Kann nicht alle Werte berechnen, die im Voraus wiederholt werden sollen
Eine Generatorfunktion wird durch einen Funktionsaufruf zu einem Iteratorobjekt.
gen = my_generator()
gen.__next__() # 1
gen.__next__() # 2
gen.__next__() # 3
gen.__next__() # StopIteration
Yield gibt die Kontrolle an die Seite zurück, die next () aufgerufen hat. Lassen Sie uns den Verarbeitungsablauf mit der print-Anweisung überprüfen, wie unten gezeigt.
generator_sample.py
def my_generator():
print('before yield')
yield 1
print('yielded 1')
yield 2
print('yielded 2')
yield 3
print('yielded 3, finished')
def main():
gen = my_generator()
print('start')
v1 = gen.__next__()
print('called __next__(), v1=%s' % v1)
v2 = gen.__next__()
print('called __next__(), v2=%s' % v2)
v3 = gen.__next__()
print('called __next__(), v3=%s' % v3)
v4 = gen.__next__() # should be exception
main()
Das Ausführungsergebnis ist wie folgt.
start
before yield
called __next__(), v1=1
yielded 1
called __next__(), v2=2
yielded 2
called __next__(), v3=3
yielded 3, finished
Traceback (most recent call last):
File "./generator_sample.py", line 21, in <module>
main()
File "./generator_sample.py", line 19, in main
v4 = gen.__next__() # should be exception
StopIteration
Iterierbare können einfach mit integrierten Funktionen wie der Notation Liste / Tupel / Satz / Liste verknüpft werden.
Sie können den obigen einfachen Generator beispielsweise einfach in ein Listenobjekt mit einem Wert wie "[1, 2, 3]" konvertieren, indem Sie ihn an die Funktion "list ()" übergeben. Gleiches gilt für Tupel und Set.
def my_generator():
yield 1
yield 2
yield 3
def my_generator2():
yield 10
yield 10
yield 20
print(list(my_generator())) # => [1, 2, 3]
print([v * 2 for v in my_generator()]) # => [2, 4, 6]
print(set(my_generator2())) # => set([10, 20])
Natürlich können nicht nur Generatoren, die mit "Yield" implementiert sind, sondern auch Iteratoren, die mit "next ()" und "Return" implementiert sind, auch mit integrierten Funktionen arbeiten.
itertools
Einführung in Python, da es eine Bibliothek namens [itertools] gibt (https://docs.python.org/ja/3/library/itertools.html), mit der Sie auf einfache Weise verschiedene Vorgänge ausführen können, indem Sie Iter-Objekte kombinieren. Ich werde es verlassen. Ich denke, dies wird hauptsächlich für integrierte Daten wie list / tuple verwendet, ohne einen Iterator selbst zu implementieren. Daher ist es auch dann praktisch, wenn Sie keinen Iterator implementieren.
Zum Beispiel ist es einfach, [alle Kombinationen] von "[1, 2, 3]" und "[" a "," b "] aufzulisten (http://qiita.com/tomotaka_ito/items/5a545423eac654a5b6f5). Ich kann es schaffen
more_itertools
Es gibt auch eine nicht standardmäßige PyPI-Bibliothek namens more_itertools. Es enthält viele nützliche Funktionen, die nicht in itertools enthalten sind. Es gibt "Chunked", das alle N Teile zusammenfasst, und "ilen", das die Zahl durch Drehen des Iterators zählt.
Sie müssen es installieren, um es verwenden zu können.
$ pip install more-itertools
Es gibt auch Qiita-Artikel, der itertools / more_itertools einführt und erklärt, daher denke ich, dass es hilfreich sein wird.
Sobald der Generator in der "for" -Schleife gedreht ist, erscheinen die Elemente nicht in der zweiten und den folgenden "for" -Schleifen.
Wenn Sie die Generatorfunktion beliebig oft ohne Nebenwirkungen aufrufen möchten, Es kann nützlich sein, die in Ich möchte den Python-Generator viele Male wiederholen beschriebene Technik zu verwenden.
__iter__ ()
wird aufgerufen, wenn das Objekt als Iteratorkontext ausgewertet wird
--Generatoren sind eine Art Iterator und werden mit "Yield" implementiertitertools
ist auch sehr praktischRecommended Posts