92 votes

Quand est-ce pas un bon moment pour utiliser python générateurs?

C'est plutôt l'inverse de Ce que vous pouvez utiliser Python générateur de fonctions?: python générateurs, générateur d'expressions, et l' itertools module sont certains de mes fonctionnalités préférées de python ces jours-ci. Ils sont particulièrement utiles lors de la configuration de chaînes d'opérations à effectuer sur un gros tas de données--j'ai souvent utiliser lors du traitement de la DSV fichiers.

Alors, quand est-ce pas un bon moment pour utiliser un groupe électrogène, ou un générateur d'expression, ou un itertools fonction?

  • Quand dois-je préfère zip() sur itertools.izip(), ou
  • range() sur xrange(), ou
  • [x for x in foo] sur (x for x in foo)?

Évidemment, nous avons finalement besoin pour "résoudre" un générateur en données réelles, généralement par la création d'une liste ou d'une itération sur elle avec une non-générateur de boucle. Parfois, nous avons juste besoin de connaître la longueur. Ce n'est pas ce que je vous demande.

Nous utilisons des générateurs de sorte que nous ne sommes pas affecter de nouvelles listes en mémoire pour des données provisoires. En particulier, cela a du sens pour de grands ensembles de données. Est-il judicieux pour les petits jeux de données? Est-il perceptible mémoire/cpu compromis?

Je suis surtout intéressé si quelqu'un a fait un certain profilage sur ce, à la lumière de l'oeil-ouverture du débat de compréhension de liste rendement en fonction map() et filter().

44voto

Ryan Ginstrom Points 8354

En général, ne pas utiliser de générateur lorsque vous avez besoin de la liste des opérations, comme len(), inversé(), et ainsi de suite.

Il peut aussi y avoir des moments où vous ne voulez pas d'évaluation différée (par exemple, de faire tous les calculs à l'avant de sorte que vous pouvez libérer une ressource). Dans ce cas, une liste d'expression peut-être mieux.

29voto

Jerub Points 17488

Profil De, Profil De Profil De.

Profilage votre code est la seule façon de savoir si ce que vous faites a aucun effet.

La plupart des usages de xrange, générateurs, etc sont plus statiques, les petits jeux de données. C'est seulement lorsque vous obtenez de grands ensembles de données que cela fait vraiment une différence. range() vs xrange() est la plupart du temps juste une question de faire le code de chercher un tout petit peu plus laid, et de ne pas perdre quoi que ce soit, et peut-être gagner quelque chose.

Profil De, Profil De Profil De.

17voto

Steven Huwig Points 8029

Vous ne devriez jamais favoriser zip sur izip, range sur xrange, ou des interprétations de la liste de plus de générateur de compréhensions. En Python 3.0 range a xrange-comme la sémantique et l' zip a izip-comme sémantique.

Interprétations de la liste sont effectivement plus clair comme de l' list(frob(x) for x in foo) pour les fois que vous besoin d'une liste.

7voto

monkut Points 14549

Comme vous le mentionnez, "en particulier, Cela a du sens pour de grands ensembles de données", je pense que cela répond à votre question.

Si votre ne pas frapper les murs, en terme de performance, je m'en tiendrais à des listes et des fonctions standard. Puis, quand vous rencontrez des problèmes avec la performance de la substitution.

6voto

Ryan Ginstrom Points 8354

Concernant les performances: si vous utilisez psyco, les listes peuvent être un peu plus rapide que ceux des producteurs. Dans l'exemple ci-dessous, les listes sont près de 50% plus rapide lors de l'utilisation de psyco.complet (le)

import psyco
import time
import cStringIO

def time_func(func):
    """The amount of time it requires func to run"""
    start = time.clock()
    func()
    return time.clock() - start

def fizzbuzz(num):
    """That algorithm we all know and love"""
    if not num % 3 and not num % 5:
        return "%d fizz buzz" % num
    elif not num % 3:
        return "%d fizz" % num
    elif not num % 5:
        return "%d buzz" % num
    return None

def with_list(num):
    """Try getting fizzbuzz with a list comprehension and range"""
    out = cStringIO.StringIO()
    for fibby in [fizzbuzz(x) for x in range(1, num) if fizzbuzz(x)]:
        print >> out, fibby
    return out.getvalue()

def with_genx(num):
    """Try getting fizzbuzz with generator expression and xrange"""
    out = cStringIO.StringIO()
    for fibby in (fizzbuzz(x) for x in xrange(1, num) if fizzbuzz(x)):
        print >> out, fibby
    return out.getvalue()

def main():
    """
    Test speed of generator expressions versus list comprehensions,
    with and without psyco.
    """

    #our variables
    nums = [10000, 100000]
    funcs = [with_list, with_genx]

    # first, try without psyco
    print "without psyco"
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

    # now with pscyo
    print "with psyco"
    psyco.full()
    for num in nums:
        print "  number:", num
        for func in funcs:
            print func.__name__, time_func(lambda : func(num)), "seconds"
        print

if __name__ == "__main__":
    main()

Résultats:

without psyco
  number: 10000
with_list 0.0519102208309 seconds
with_genx 0.0535933367509 seconds

  number: 100000
with_list 0.542204280744 seconds
with_genx 0.557837353115 seconds

with psyco
  number: 10000
with_list 0.0286369007033 seconds
with_genx 0.0513424889137 seconds

  number: 100000
with_list 0.335414877839 seconds
with_genx 0.580363490491 seconds

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