130 votes

Python: imprimer une expression génératrice?

Dans le Python, shell, si je entrer une liste de compréhension telles que:

>>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]

Je reçois un bien imprimée résultat:

['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

Même pour un dictionnaire de compréhension:

>>> {x:x*2 for x in range(1,10)}
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

Si j'entre un générateur d'expression, je reçois pas une réponse favorable:

>>> (x for x in string.letters if x in (y for y in "BigMan on campus"))
<generator object <genexpr> at 0x1004a0be0>

Je sais que je peux faire ceci:

>>> for i in _: print i,
a c g i m n o p s u B M

Autre que celui (ou l'écriture d'une fonction d'assistance) puis-je évaluer facilement et l'impression que l'objet de générateur dans le shell interactif?

188voto

Lennart Regebro Points 52510

Réponse rapide:

Faire list() autour d'un générateur d'expression est (presque) exactement équivalent à [] des crochets autour d'elle. Donc oui, vous pouvez le faire

>>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))

Mais vous pouvez tout aussi bien le faire

>>> [x for x in string.letters if x in (y for y in "BigMan on campus")]

Oui, qui fera tourner le générateur d'expression dans une compréhension de liste. C'est la même chose et la liste d'appel() sur celui-ci. Ainsi, la manière de faire un générateur d'expression dans une liste est de mettre des parenthèses autour d'elle.

Explication détaillée:

Un générateur d'expression est un "nu" for expression. Comme suit:

x*x for x in range(10)

Maintenant, vous ne pouvez pas coller que sur une ligne, vous obtiendrez une erreur de syntaxe. Mais vous pouvez mettre des parenthèses autour d'elle.

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7485464>

Cela est parfois appelé un générateur de compréhension, même si je pense que le nom officiel est toujours générateur d'expression, il n'y a pas vraiment de différence, les parenthèses ne sont là que pour rendre la syntaxe valide. Vous n'en avez pas besoin si vous êtes de passage dans le seul paramètre à une fonction, par exemple:

>>> sorted(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Fondamentalement, tous les autres interprétations disponibles en Python 3 et Python 2.7 est juste sucre syntaxique autour d'un générateur d'expression. Ensemble des compréhensions:

>>> {x*x for x in range(10)}
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

>>> set(x*x for x in range(10))
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

Dict interprétations:

>>> dict((x, x*x) for x in range(10))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

>>> {x: x*x for x in range(10)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

Et les interprétations de la liste sous Python 3:

>>> list(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Sous Python 2, interprétations de la liste n'est pas juste de sucre syntaxique. Mais la seule différence, c'est que x sera sous Python 2 de fuite dans l'espace de noms.

>>> x
9

Alors que sous Python 3, vous aurez

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Cela signifie que la meilleure façon d'obtenir une impression agréable de le contenu de votre générateur d'expression en Python est de faire une liste de compréhension de sortir! Toutefois, cela ne fonctionne évidemment pas si vous avez déjà un objet de générateur. Faire cela va juste faire une liste d'un générateur:

>>> foo = (x*x for x in range(10))
>>> [foo]
[<generator object <genexpr> at 0xb7559504>]

Dans ce cas, vous aurez besoin de faire appel list():

>>> list(foo)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Bien que cela fonctionne, mais c'est un peu stupide:

>>> [x for x in foo]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

19voto

dogtato Points 191

Contrairement à une liste ou à un dictionnaire, un générateur peut être infini. Cela ne fonctionnerait pas:

 def gen():
    x = 0
    while True:
        yield x
        x += 1
g1 = gen()
list(g1)   # never ends
 

De plus, la lecture d'un générateur le change, il n'y a donc pas de moyen idéal pour le voir. Pour voir un exemple de la sortie du générateur, vous pouvez faire

 g1 = gen()
[g1.next() for i in range(10)]
 

17voto

Björn Pollex Points 41424

Vous pouvez simplement envelopper l'expression dans un appel à list :

 >>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']
 

17voto

lbolla Points 3665

Ou vous pouvez toujours map sur un itérateur, sans avoir besoin de construire une liste intermédiaire:

 >>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus")))
acgimnopsuBM
 

2voto

Andreas Jung Points 1
>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

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