Am Ende des folgenden Artikels schrieb ich, dass der Generator containerisiert werden sollte.
Diesmal werde ich das erklären.
Erstellen Sie zunächst einen Generator, der die Fibonacci-Zahl wie zuvor generiert. In den Kommentaren des vorherigen Artikels wurde mir eine ausgefeilte Schreibweise beigebracht, daher werde ich diese verwenden.
Python
#Generator
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
#Containergenerator
class FibonacciGenerator(object):
def __iter__(self):
a, b = 0, 1
while True:
yield a
a, b = b, a + b
Diese geben das gleiche Ergebnis aus.
Python
for fib in fibonacci_generator():
if fib > 1000:
break
print fib,
print
for fib in FibonacciGenerator():
if fib > 1000:
break
print fib,
Ergebnis
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
Beachten Sie, dass sich die beiden obigen for-Anweisungen nur im Generator unterscheiden. Es ist mühsam, diesen Code jedes Mal zu schreiben, wenn der Generator wechselt. Machen wir ihn also zu einer Funktion.
Python
def print_fib(fib_iterator, limit = 1000):
for fib in fib_iterator:
if fib > limit:
break
print fib,
print
print_fib(fibonacci_generator())
print_fib(FibonacciGenerator())
Ergebnis
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
Es war ordentlich, eine Funktion zum Empfangen des Generators zu erstellen.
Ändern wir nun diese Funktion, um den Inhalt des Generators zweimal anzuzeigen.
Python
def print_fib_twice(fib_iterator, limit = 100):
print "[1]",
for fib in fib_iterator:
if fib > limit:
break
print fib,
print " [2]",
for fib in fib_iterator:
if fib > limit:
break
print fib,
print
print_fib_twice(fibonacci_generator())
print_fib_twice(FibonacciGenerator())
Ergebnis
[1] 0 1 1 2 3 5 8 13 21 34 55 89 [2]
[1] 0 1 1 2 3 5 8 13 21 34 55 89 [2] 0 1 1 2 3 5 8 13 21 34 55 89
Der Generator, der nicht containerisiert ist, zeigt den Inhalt des zweiten Mal nicht an. Der Grund dafür ist, dass, wenn Sie den Generator so wie er ist verwenden, derselbe beim ersten und beim zweiten Mal wiederverwendet wird. Der containerisierte Generator erstellt für jede Schleife einen neuen Generator. Dies ist leicht zu verstehen, wenn Sie Folgendes versuchen.
Python
def print_fib_twice2(fib_iterator, limit1, limit2):
print "[1]",
for fib in fib_iterator:
if fib > limit1:
break
print fib,
print " [2]",
for fib in fib_iterator:
if fib > limit2:
break
print fib,
print
print_fib_twice2(fibonacci_generator(), limit1 = 100, limit2 = 400)
print_fib_twice2(FibonacciGenerator(), limit1 = 100, limit2 = 400)
Ergebnis
[1] 0 1 1 2 3 5 8 13 21 34 55 89 [2] 233 377
[1] 0 1 1 2 3 5 8 13 21 34 55 89 [2] 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Auf diese Weise verursacht der Generator einen unerwarteten Fehler, wenn er an eine Funktion übergeben wird, die intern mehrfach verwendet wird. Daher ist es im Allgemeinen sicherer, daraus einen Behälter zu machen.
Im Gegenteil, wenn Sie eine Funktion schreiben, die einen Iterator empfängt, ist es besser zu überprüfen, ob sie containerisiert ist.
Sie können feststellen, ob ein Iterator containerisiert ist, indem Sie iter ()
zweimal anwenden und prüfen, ob verschiedene Iteratoren zurückgegeben werden.
Python
def print_fib_twice3(fib_iterator, limit = 100):
if iter(fib_iterator) is iter(fib_iterator):
raise TypeError("Must supply a container")
print "[1]",
for fib in fib_iterator:
if fib > limit:
break
print fib,
print " [2]",
for fib in fib_iterator:
if fib > limit:
break
print fib,
print
Python
print_fib_twice3(fibonacci_generator())
Ergebnis
TypeError: Must supply a container
Python
print_fib_twice3(FibonacciGenerator())
Ergebnis
[1] 0 1 1 2 3 5 8 13 21 34 55 89 [2] 0 1 1 2 3 5 8 13 21 34 55 89
Dies verhindert unbeabsichtigtes Verhalten.
Enjoy!
Recommended Posts