enumerate () - création d'un générateur en Python

88

J'aimerais savoir ce qui se passe lorsque je passe le résultat d'une fonction de générateur à enumerate () de python. Exemple:

def veryBigHello():
    i = 0
    while i < 10000000:
        i += 1
        yield "hello"

numbered = enumerate(veryBigHello())
for i, word in numbered:
    print i, word

L'énumération est-elle répétée paresseusement, ou est-ce qu'elle insère tout dans la première? Je suis sûr à 99,999% que c'est paresseux, puis-je le traiter exactement de la même manière que la fonction générateur, ou dois-je faire attention à quoi que ce soit?

Adam
la source
1
Je suppose que vous voulez incrémenter i dans veryBigHello.
robert
@robert: si je ne me trompe pas, je augmente automatiquement
the_drow
@the_drow Pas dans la veryBigHellofonction elle-même.
Will McCutchen
1
@Will: Oh, c'est exact. Mais ce n'est que pinailler. C'est un exemple. Corrigé de toute façon.
the_drow

Réponses:

103

C'est paresseux. C'est assez facile de prouver que c'est le cas:

>>> def abc():
...     letters = ['a','b','c']
...     for letter in letters:
...         print letter
...         yield letter
...
>>> numbered = enumerate(abc())
>>> for i, word in numbered:
...     print i, word
...
a
0 a
b
1 b
c
2 c
Dave Webb
la source
Est-ce Python 2 ou 3 (ou les deux)? Est-ce paresseux dans les deux? Je l' ai testé sur Python 2 et il est paresseux.
becko le
2
J'ai testé cela sur Python 3.5.2, et il évalue paresseusement.
gobernador
42

C'est encore plus facile à dire que l'une ou l'autre des suggestions précédentes:

$ python
Python 2.5.5 (r255:77872, Mar 15 2010, 00:43:13)
[GCC 4.3.4 20090804 (release) 1] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> abc = (letter for letter in 'abc')
>>> abc
<generator object at 0x7ff29d8c>
>>> numbered = enumerate(abc)
>>> numbered
<enumerate object at 0x7ff29e2c>

Si enumerate n'effectuait pas d'évaluation différée, il renverrait [(0,'a'), (1,'b'), (2,'c')]ou un équivalent (presque).

Bien sûr, enumerate n'est en réalité qu'un générateur sophistiqué:

def myenumerate(iterable):
   count = 0
   for _ in iterable:
      yield (count, _)
      count += 1

for i, val in myenumerate((letter for letter in 'abc')):
    print i, val
Wayne Werner
la source
2
Merci pour cette explication. J'ai eu un peu de mal à trouver la réponse acceptée. Au moins jusqu'à ce que je voie le vôtre.
Trendsetter37
13

Puisque vous pouvez appeler cette fonction sans sortir des exceptions de mémoire, c'est définitivement paresseux

def veryBigHello():
    i = 0
    while i < 1000000000000000000000000000:
        yield "hello"

numbered = enumerate(veryBigHello())
for i, word in numbered:
    print i, word
Nikolaus Gradwohl
la source
0

Alternative à la vieille école puisque j'utilisais un générateur écrit par quelqu'un d'autre (sklearn) qui ne fonctionnait pas avec les approches ici.

i=(-1)
for x in some_generator:
    i+=1
HashRocketSyntax
la source