Iterables und Generatoren (yield)

Listen, Dicts, etc, sind sogenannte Iterables, d.h. alles über was man in einer for ... in ... Schleife drüberlaufen kann, also z.B.:
mylist = [x*x for x in range(3)]
for i in mylist:
   print(i)

mylist
[0, 1, 4]

Bei Listen werden alle Elemente der Liste erzeugt und im Speicher abgelegt, das kann ggf. sehr viel sein.

Als Alternative gibt es Generators:

mygenerator = (x*x for x in range(3))
for i in mygenerator:
   print(i)

mygenerator
<generator object <genexpr> at 0x7f63a2c05320>
Verwendung hier fast identisch, nur Erzeugung mit runden Klammern statt eckigen. Und es wird Generator-Objekt angelegt, das man benutzen kann um einmal die Werte nacheinander abzurufen, es wird dabei jeweils nur das aktuelle Element angelegt, und am Ende ist das Generator Objekt fertig, d.h. man kann mit for i in mygenerator: nicht nochmal durchlaufen.

Man kann diese Funktionalität auch mittels sogenanter Generator-Funktionen und yield erreichen:

# a generator that yields items instead of returning a list
def firstnsq(n):
    num = 0
    while num < n:
        yield num*num
        num += 1

mygen = firstnsq(3)
for i in mygen:
   print(i)
Das Key-word yield entspricht etwa dem return bei normalen Funktionen, nur der Ablauf ist anders:

Statt mit for ... in ... Schleife kann man auch mit next(...) die einzelnen Werte abrufen:

mygen = firstnsq(3)
mygen
<generator object firstnsq at 0x7f63a2c05140>
next(mygen)
0
next(mygen)
0
...

Mehr dazu in dieser Erklärung.