Maison  >  Article  >  développement back-end  >  Explication détaillée des générateurs en Python

Explication détaillée des générateurs en Python

巴扎黑
巴扎黑original
2017-06-23 15:10:061427parcourir

1. Qu'est-ce qu'un générateur

Avec la génération de liste, on peut 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 1 million 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 sera gaspillé. Ainsi, 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 élimine le besoin de créer une liste complète, économisant ainsi beaucoup d’espace. En Python, ce mécanisme de bouclage et de calcul à la fois s'appelle un générateur : générateur.

2. Créer une méthode de générateur

Méthode 1

Il existe de nombreuses façons de créer un générateur. La première méthode est très simple, il suffit de changer le [ ] d'une génération de liste en ( )

La différence entre créer L et G est uniquement le [ ] et ( ), L est une liste et G est un générateur. On peut imprimer directement chaque élément de L, mais comment imprimer chaque élément de G ? Si vous souhaitez les imprimer un par un, vous pouvez obtenir la prochaine valeur de retour du générateur via la fonction next() :


Résultat d'exécution :

Résultat d'exécution :

Le générateur enregistre l'algorithme, et chaque fois que next( est appelé G), calculez la valeur de l'élément suivant de G jusqu'à ce que le dernier élément soit calculé. Lorsqu'il n'y a plus d'éléments, une exception StopIteration est levée. Bien sûr, ce type d'appel continu à next() est vraiment anormal. La bonne méthode consiste à utiliser une boucle for, car le générateur est également un objet itérable. Ainsi, après avoir créé un générateur, nous n'appelons pratiquement jamais next(), mais nous le parcourons dans une boucle for et nous n'avons pas besoin de nous soucier de l'exception StopIteration.

Méthode 2

le générateur est très puissant. Si l'algorithme de calcul est relativement complexe et ne peut pas être implémenté à l'aide d'une boucle for similaire à la génération de liste, il peut également être implémenté à l'aide d'une fonction.

Par exemple, dans la célèbre séquence de Fibonacci, à l'exception du premier et du deuxième nombres, n'importe quel nombre peut être obtenu en additionnant les deux premiers nombres :

1, 1, 2, 3, 5 , 8, 13, 21, 34, ...

La séquence de Fibonacci ne peut pas être écrite en utilisant la génération de liste, mais il est facile de l'imprimer à l'aide d'une fonction :


Résultat d'exécution :

En regardant attentivement, vous pouvez voir que la fonction fib est réellement définie. Après avoir compris les règles de calcul de la séquence de Fibonacci, vous peut partir du premier élément et calculer les éléments suivants. Cette logique est en fait très similaire au générateur.

En d'autres termes, la fonction ci-dessus n'est qu'à un pas du générateur. Pour transformer la fonction fib en générateur, changez simplement print(b) pour rendement b :


Résultats en cours d'exécution :

Dans l'exemple de fib ci-dessus, si nous continuons à appeler rendement pendant la boucle, elle continuera à être interrompue. Bien sûr, vous devez définir une condition pour que la boucle quitte la boucle, sinon un nombre infini sera répertorié. De même, après avoir changé la fonction en générateur, nous n'utilisons pratiquement jamais next() pour obtenir la prochaine valeur de retour, mais utilisons directement la boucle for pour itérer :

Résultats d'exécution :

Mais lors de l'appel du générateur à l'aide d'une boucle for, j'ai constaté que je ne pouvais pas obtenir la valeur de retour de l'instruction return du générateur. Si vous souhaitez obtenir la valeur de retour, vous devez capturer l'erreur StopIteration. La valeur de retour est incluse dans la valeur de StopIteration :


Résultat d'exécution :

3.send

Exemple : lors de l'exécution de rendement, la fonction gen est temporairement enregistrée et renvoie la valeur de i ; temp reçoit la prochaine fois que c.send("python"), la valeur envoyée par send, c .next() est équivalent à c.send(Aucun)

Utiliser la fonction suivante


Résultat d'exécution :

Utiliser la méthode __next__()


Résultat d'exécution :

Utiliser send

Résultat d'exécution :

4. Implémenter le multitâche

Simuler implémentation multitâche Un : Coroutine


Résultat en cours d'exécution :

Résumé

Generator est une fonction qui mémorise la position dans le corps de la fonction lors de son dernier retour. Le deuxième (ou nième) appel à une fonction génératrice saute au milieu de la fonction, laissant toutes les variables locales inchangées par rapport à l'appel précédent.

Un générateur "se souvient" non seulement de l'état de ses données ; un générateur "se souvient" également de sa position dans une construction de contrôle de flux (en programmation impérative, cette construction n'est pas seulement une valeur de données).

Caractéristiques du générateur :

1. Économiser de la mémoire

2 Lors de l'itération jusqu'à l'appel suivant, les paramètres utilisés sont tous conservés la première fois, c'est-à-dire. pour dire, les paramètres de tous les appels de fonction sont conservés lorsqu'ils sont appelés pour la première fois, plutôt que nouvellement créés

5 Itérateur

L'itération est utilisée pour accéder aux éléments de collection d'une manière. Un itérateur est un objet qui mémorise la position d'un parcours. L'objet itérateur commence à accéder à partir du premier élément de la collection jusqu'à ce que tous les éléments aient été accédés. Les itérateurs ne peuvent qu'avancer et non reculer.

1. Objets itérables

Les types de données qui agissent directement sur les boucles for sont les suivants :

Un type est constitué des types de données de collection, tels que list, tuple, dict , set, str, etc.;

La première catégorie est le générateur, y compris le générateur et la fonction génératrice avec rendement.

Ces objets qui peuvent être directement utilisés dans les boucles for sont collectivement appelés objets itérables : Iterable.

2. Déterminer si itérable

Vous pouvez utiliser isinstance() pour déterminer si un objet est un objet itérable :


Résultat en cours d'exécution :

Le générateur peut non seulement agir sur la boucle for, mais peut aussi être appelé en continu par la fonction next() et renvoyer la valeur suivante, jusqu'à ce que finalement une erreur StopIteration est générée pour indiquer qu'il ne peut pas continuer à revenir à la valeur suivante.

3. Itérateur

Un objet qui peut être appelé par la fonction next() et renvoie continuellement la valeur suivante est appelé un itérateur : Itérateur.


Résultat d'exécution :

Fonction 4.iter()

Générateur Ils sont tous des objets Iterator, mais bien que list, dict et str soient itérables, ils ne sont pas des itérateurs.

Pour convertir list, dict, str et autres Iterables en Iterator, vous pouvez utiliser la fonction iter() :


Résultat d'exécution :

Résumé

·Tous les objets pouvant être utilisés dans les boucles for sont de type Iterable

·Tous les objets pouvant être utilisés dans la fonction next() sont de type Iterator

·Les types de données de collection tels que list, dict, str, etc. sont Iterable mais pas Iterator, mais vous pouvez obtenir un objet Iterator via la fonction iter().

·Le but est de réduire le contenu occupé lors de l'utilisation des collections.

6. Clôture

1. Référence de la fonction


Résultat de l'exécution :

Illustration :

2. Qu'est-ce qu'une fermeture


Résultat de l'exécution :

3. Regardez un exemple pratique de fermeture :


Résultat d'exécution :

Dans cet exemple, la ligne de fonction et les variables a et b forment une fermeture. Lors de la création de la fermeture, nous précisons les valeurs de ces deux variables via les paramètres a et b de line_conf. De cette manière, nous déterminons la forme finale de la fonction (y = x + 1 et y = 4x + 5). Il suffit de transformer les paramètres a et b pour obtenir différentes fonctions d'expression en ligne droite. De là, nous pouvons voir que les fermetures ont également pour effet d’améliorer la réutilisabilité du code.

S'il n'y a pas de fermeture, nous devons spécifier a, b, x chaque fois que nous créons une fonction de ligne droite. De cette façon, nous devons transmettre plus de paramètres, ce qui réduit également la portabilité du code

Si vous rencontrez des problèmes pendant le processus d'apprentissage ou si vous souhaitez obtenir des ressources d'apprentissage, vous êtes invités à rejoindre le groupe d'échange d'apprentissage
626062078, on apprend Python ensemble !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn