enumerate () - gerando um gerador em Python


88

Gostaria de saber o que acontece quando passo o resultado de uma função do gerador para enumerate () do python. Exemplo:

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

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

A enumeração é iterada preguiçosamente ou ela inunda tudo na primeira? Tenho 99,999% de certeza que é preguiçoso, então posso tratá-lo exatamente como a função do gerador ou preciso tomar cuidado com alguma coisa?


1
Presumo que você queira incrementar i em veryBigHello.
robert

@robert: se não estou
enganado

@the_drow Não na veryBigHelloprópria função.
Will McCutchen

1
@Will: Oh, correto. Mas isso é apenas picuinhas. É um exemplo. Corrigido de qualquer maneira.
the_drow

Respostas:


103

É preguiçoso. É bastante fácil provar que é o caso:

>>> 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

Este é Python 2 ou 3 (ou ambos)? É preguiçoso em ambos? Eu testei no Python 2 e é preguiçoso.
becko

2
Eu testei isso no Python 3.5.2 e ele avalia lentamente.
gobernador

42

É ainda mais fácil dizer do que qualquer uma das sugestões anteriores:

$ 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>

Se enumerate não executasse uma avaliação preguiçosa, ele retornaria [(0,'a'), (1,'b'), (2,'c')]ou algum (quase) equivalente.

Claro, enumerar é apenas um gerador sofisticado:

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
Obrigado por esta explicação. Eu tive um pouco de dificuldade em descobrir a resposta aceita. Pelo menos até ver o seu.
trendsetters37

13

Uma vez que você pode chamar esta função sem obter exceções de memória, é definitivamente preguiçoso

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

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

0

Alternativa da velha escola, já que eu estava usando um gerador que outra pessoa (sklearn) escreveu que não funcionava com as abordagens aqui.

i=(-1)
for x in some_generator:
    i+=1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.