240 votes

Ce que vous pouvez utiliser fonctions générateur Python pour ?

Je commence à apprendre Python et je suis tombé sur les fonctions de générateur, ceux qui ont une instruction yield en eux. Je veux savoir quels types de problèmes que ces fonctions sont vraiment bonnes à résoudre.

271voto

Thomas Wouters Points 38811

Les générateurs de vous donner de l'évaluation différée. Vous les utilisez par itération sur eux, soit explicitement, avec les "pour" ou implicitement par le passant à toute fonction ou de la construction qui se répète. Vous pouvez penser à des générateurs de retour de plusieurs éléments, comme si elles retournent une liste, mais au lieu de les renvoyer tous à la fois, ils reviennent un par un, et le générateur de fonction est mise en pause jusqu'à l'élément suivant est demandé.

Les générateurs sont bonnes pour le calcul de grands ensembles de résultats (en particulier des calculs impliquant des boucles d'eux-mêmes) où vous ne savez pas si vous allez avoir besoin de tous les résultats, ou si vous ne voulez pas à allouer la mémoire pour tous les résultats en même temps. Ou pour les situations où le générateur utilise un autre générateur, ou consomme de certains autres ressources, et c'est plus pratique si c'est arrivé aussi tard que possible.

Une autre utilisation de générateurs (c'est vraiment le même) est de remplacer les rappels à l'itération. Dans certaines situations, vous voulez une fonction pour faire beaucoup de travail et parfois de rapport à l'appelant. Traditionnellement, vous pouvez utiliser une fonction de rappel pour cette. Vous passer de ce rappel pour le travail-fonction et il serait périodiquement appel de ce rappel. Le générateur approche, c'est que la fonction (maintenant un générateur) ne sait rien à propos de la fonction de rappel, et simplement les rendements à chaque fois qu'il veut rendre compte de quelque chose. L'appelant, au lieu d'écrire un rappel séparée et de passage que pour le travail-fonction, fait tout le travail dans un peu de "pour" boucle autour de la génératrice.

Par exemple, disons que vous avez écrit un "système de fichiers de recherche" du programme. Vous pourriez effectuer la recherche dans son intégralité, de collecter les résultats et de les afficher un par un. Tous les résultats doivent être recueillies avant vous a montré le premier, et tous les résultats seraient en mémoire en même temps. Ou vous pouvez afficher les résultats pendant que vous les trouver, ce qui serait plus efficace en terme de mémoire et beaucoup plus conviviale pour l'utilisateur. Ce dernier pourrait être fait en passant le résultat de la fonction d'impression du système de fichiers la fonction de recherche, ou il pourrait être fait simplement en faisant la fonction de recherche d'un générateur et d'itérer sur le résultat.

Si vous voulez voir un exemple de ces deux approches, voir l'os.chemin d'accès.marche() (l'ancien système de fichiers-la marche de la fonction avec le rappel) et de l'os.marche() (le nouveau système de fichiers de marche du générateur.) Bien sûr, si vous avez vraiment envie de collecter tous les résultats dans une liste, le générateur approche est trivial de le convertir à la big liste:

big_list = list(the_generator)

97voto

nosklo Points 75862

L'une des raisons d'utiliser le générateur est de rendre la solution plus claire pour certains type de solutions.

L'autre est de traiter les résultats en un à la fois, en évitant la construction d'énormes listes de résultats que vous le feriez processus séparés de toute façon.

Si vous avez un de fibonacci jusqu'à la n de la fonction comme ceci:

# function version
def fibon(n):
    a = b = 1
    result = []
    for i in xrange(n):
        result.append(a)
        a, b = b, a + b
    return result

Vous pouvez plus facilement écrire la fonction comme ceci:

# generator version
def fibon(n):
    a = b = 1
    for i in xrange(n):
        yield a
        a, b = b, a + b

La fonction est claire. Et si vous utilisez la fonction comme ceci:

for x in fibon(1000000):
    print x,

dans cet exemple, si vous utilisez le générateur de version, l'ensemble 1000000 élément de la liste ne sera pas créé à tous, juste une valeur à la fois. Qui ne serait pas le cas lors de l'utilisation de la version de liste, où une liste serait a créé en premier.

45voto

Nickolay Points 14384

Consultez la section « Motivation » dans 255 PEP.

Une utilisation non évidente de générateurs est création de fonctions interruptibles, qui vous permet de faire des choses comme mettre à jour l’interface utilisateur ou exécuter des tâches en plusieurs « simultanément » (entrelacés, en fait) tout en n’utilisant ne pas fils.

28voto

Rafał Dowgird Points 16600

Mise en mémoire tampon. Quand il est efficace pour extraire les données en gros morceaux, mais traitez-la en petits morceaux, puis un générateur peut aider :

Ce qui précède permet de séparer facilement mise en mémoire tampon de traitement. La fonction de consommation peut maintenant juste obtenir les valeurs une à une sans se soucier de la mise en mémoire tampon.

21voto

dF. Points 29787

L'explication simple: Considérons un for déclaration

for item in iterable:
   do_stuff()

Beaucoup de temps, tous les éléments en iterable n'a pas besoin d'être là depuis le début, mais peut être généré à la volée comme vous en avez besoin. Cela peut être beaucoup plus efficace dans les deux

  • l'espace (vous n'avez jamais besoin de stocker tous les éléments en même temps) et
  • temps (l'itération peut se terminer avant que tous les éléments sont nécessaires).

D'autres fois, vous ne savez même pas tous les éléments à l'avance. Par exemple:

for command in user_input():
   do_stuff_with(command)

Vous n'avez aucun moyen de connaître toutes les commandes de l'utilisateur à l'avance, mais vous pouvez utiliser une belle boucle comme ceci si vous avez un générateur de vous remettre les commandes:

def user_input():
    while True:
        wait_for_command()
        cmd = get_command()
        yield cmd

Avec les générateurs, vous pouvez également avoir une itération sur les suites infinies, ce qui n'est évidemment pas possible lors de l'itération sur les conteneurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X