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?


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

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

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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.