À la fin de l'article ci-dessous, j'ai écrit que le générateur devrait être conteneurisé.
Cette fois, je vais expliquer cela.
Tout d'abord, créez un générateur qui génère le nombre de Fibonacci comme auparavant. Dans le commentaire de l'article précédent, on m'a appris une méthode d'écriture sophistiquée, je vais donc l'utiliser.
Python
#Générateur
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
#Générateur conteneurisé
class FibonacciGenerator(object):
def __iter__(self):
a, b = 0, 1
while True:
yield a
a, b = b, a + b
Ceux-ci produisent le même résultat.
Python
for fib in fibonacci_generator():
if fib > 1000:
break
print fib,
print
for fib in FibonacciGenerator():
if fib > 1000:
break
print fib,
résultat
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
Notez que les deux instructions for ci-dessus ne diffèrent que dans le générateur. Il est fastidieux d'écrire ce code à chaque fois que le générateur change, alors faisons-en une fonction.
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())
résultat
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
C'était chouette de créer une fonction pour recevoir le générateur.
Modifions maintenant cette fonction pour afficher le contenu du générateur deux fois.
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())
résultat
[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
Comment, le générateur qui n'est pas conteneurisé n'affiche pas le contenu de la deuxième fois. La raison en est que si vous utilisez le générateur tel quel, le même sera réutilisé la première et la deuxième fois. Le générateur conteneurisé créera un nouveau générateur pour chaque boucle. Ceci est facile à comprendre si vous essayez ce qui suit.
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)
résultat
[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
De cette façon, si le générateur est passé à une fonction qui est utilisée plusieurs fois en interne, cela provoquera une erreur inattendue. Par conséquent, il est généralement plus sûr d'en faire un conteneur.
Au contraire, lors de l'écriture d'une fonction qui reçoit un itérateur, il vaut mieux vérifier si elle est conteneurisée. Vous pouvez déterminer si un itérateur est conteneurisé en appliquant ʻiter () `deux fois et en vérifiant si différents itérateurs sont renvoyés.
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())
résultat
TypeError: Must supply a container
Python
print_fib_twice3(FibonacciGenerator())
résultat
[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
Cela empêchera tout comportement involontaire.
Enjoy!
Recommended Posts