générateur

1. Pourquoi avons-nous besoin d'un générateur

Grâce à l'apprentissage ci-dessus, nous pouvons connaître la formule de génération de liste et créer directement une liste. Cependant, en raison de contraintes de mémoire, la capacité de la liste est définitivement limitée. De plus, créer une liste contenant 10 millions d'éléments prend non seulement beaucoup d'espace de stockage, mais si nous n'avons besoin d'accéder qu'aux premiers éléments, l'espace occupé par la plupart des éléments suivants est gaspillé.

Donc, si les éléments de la liste peuvent être calculés selon un certain algorithme, pouvons-nous calculer en continu les éléments suivants pendant la boucle ? Cela permet d'économiser beaucoup d'espace en n'ayant pas besoin de créer une liste complète. En Python, ce mécanisme de bouclage et de calcul à la fois s'appelle un générateur : générateur.

En Python, les fonctions qui utilisent le rendement sont appelées générateurs.

Différent des fonctions ordinaires, un générateur est une fonction qui renvoie un itérateur et ne peut être utilisée que pour des opérations itératives. Il est plus facile de comprendre qu'un générateur est un itérateur.

Dans le processus d'appel du générateur pour qu'il s'exécute, chaque fois qu'il rencontre un rendement, la fonction fera une pause et enregistrera toutes les informations en cours d'exécution et renverra la valeur du rendement. Et continuez à courir à partir de la position actuelle la prochaine fois que la méthode next() sera exécutée.

Alors comment créer un générateur ?

2. Créer un générateur

Le moyen le plus simple et le plus simple est de changer le [] d'une génération de liste en ()

# -*- coding: UTF-8 -*-
gen= (x * x for x in range(10))
print(gen)

Le résultat de sortie :

<generator object <genexpr> at 0x0000000002734A40>

La seule différence entre la création d'une liste et d'un générateur est que le dernier L'extérieur [] et (). Mais le générateur ne crée pas réellement une liste de nombres, mais renvoie plutôt un générateur qui "rend" (rend) un élément à chaque fois qu'il est calculé. L'expression du générateur utilise "évaluation paresseuse" (évaluation paresseuse, également traduite par "évaluation retardée", je pense que cette méthode d'appel par besoin est mieux traduite par paresseuse), et n'est attribuée que lors de la récupération (évaluée), donc c'est plus de mémoire efficace lorsque la liste est longue.

Je sais donc comment créer un générateur, mais comment visualiser les éléments à l'intérieur ?

3. Parcourez les éléments du générateur

Selon notre réflexion, la boucle for est utilisée pour le parcours. D'ailleurs, nous pouvons essayer :

# -*- coding: UTF-8 -*-
gen= (x * x for x in range(10))
for num  in  gen :
print(num)

Oui, vous pouvez la parcourir directement comme ça. Bien sûr, les itérateurs ont également été mentionnés ci-dessus, alors next() peut-il être utilisé pour traverser ? Bien sûr, c'est possible.

4. Implémentez le générateur sous la forme d'une fonction

Comme mentionné ci-dessus, le moyen le plus simple et le plus simple de créer un générateur est de remplacer [] dans une génération de liste par (). Pourquoi est-il soudainement créé sous la forme d’une fonction ?

En fait, un générateur est aussi un itérateur, mais vous ne pouvez l'itérer qu'une seule fois. En effet, ils ne stockent pas toutes les valeurs en mémoire, mais génèrent les valeurs au moment de l'exécution. Vous les utilisez en les itérant, soit avec une boucle "for", soit en les transmettant à n'importe quelle fonction ou structure pouvant être itérée. Et dans les applications réelles, la plupart des générateurs sont implémentés via des fonctions. Alors comment le créer via des fonctions ?

Ne vous inquiétez pas, jetons un œil à cet exemple :

# -*- coding: UTF-8 -*-
def my_function():
    for i in range(10):
        print ( i )
my_function()

Le résultat de sortie :

0
1
2
3
4
5
6
7
8
9

Si nous devons le transformer en générateur, il nous suffit de changer print ( i ) pour donner i . Regardez de plus près Exemple modifié :

# -*- coding: UTF-8 -*-
def my_function():
    for i in range(10):
        yield i
print(my_function())

Résultat de sortie :

<generator object my_function at 0x0000000002534A40>

Cependant, cet exemple est très inadapté à l'utilisation d'un générateur et ne peut pas faire ressortir les caractéristiques du générateur. La meilleure application du générateur devrait être : vous ne le souhaitez pas. utiliser tous les générateurs en même temps. Un grand nombre d’ensembles de résultats calculés sont alloués à la mémoire, surtout si l’ensemble de résultats contient également des boucles. Parce que cela consommera beaucoup de ressources.

Par exemple, ce qui suit est un générateur qui calcule la séquence de Fibonacci :

# -*- coding: UTF-8 -*-
def fibon(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b
# 引用函数
for x in fibon(1000000):
    print(x , end = ' ')

L'effet de l'exécution :

c510424ccec9b78105579250c3f3799.pngVous voyez, exécuter un paramètre comme celui-ci ne dira pas qu'il y a un état bloqué, à cause de cette méthode. N'utilisez pas trop de ressources. Ici, le plus difficile à comprendre est que le flux d’exécution des générateurs et des fonctions est différent. Les fonctions sont exécutées séquentiellement et sont renvoyées lorsqu'elles rencontrent une instruction return ou la dernière ligne d'instructions de fonction. La fonction qui devient un générateur est exécutée à chaque fois que next() est appelée, revient lorsqu'elle rencontre une instruction rendement et continue l'exécution à partir de la dernière instruction rendement renvoyée lorsqu'elle est à nouveau exécutée.

Par exemple, cet exemple :

# -*- coding: UTF-8 -*-
def odd():
    print ( 'step 1' )
    yield ( 1 )
    print ( 'step 2' )
    yield ( 3 )
    print ( 'step 3' )
    yield ( 5 )
o = odd()
print( next( o ) )
print( next( o ) )
print( next( o ) )
输出的结果:
step 1
1
step 2
3
step 3
5

Vous pouvez voir que odd n'est pas une fonction ordinaire, mais un générateur Lors de l'exécution, elle sera interrompue lorsque le rendement est rencontré, et l'exécution continuera la prochaine fois. Après avoir exécuté rendement 3 fois, il n'y a plus de rendement à exécuter. Si vous continuez à imprimer print(next(o)), une erreur sera signalée. Les erreurs sont donc généralement capturées dans la fonction générateur.

5. Imprimer le triangle Yang Hui

En apprenant le générateur, nous pouvons directement utiliser les points de connaissance du générateur pour imprimer le triangle Yang Hui :

# -*- coding: UTF-8 -*-
def triangles( n ):         # 杨辉三角形
    L = [1]
    while True:
        yield L
        L.append(0)
        L = [ L [ i -1 ] + L [ i ] for i in range (len(L))]
n= 0
for t in triangles( 10 ):   # 直接修改函数名即可运行
    print(t)
    n = n + 1
    if n == 10:
        break

Le résultat de sortie est :

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
Formation continue
  • Recommandations de cours
  • Téléchargement du didacticiel