enumerate () - tworzenie generatora w Pythonie


88

Chciałbym wiedzieć, co się stanie, gdy przekażę wynik funkcji generatora do metody enumerate () w języku Python. Przykład:

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

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

Czy wyliczenie powtarza się leniwie, czy też siorbi wszystko w pierwszym? Jestem na 99,999% pewien, że jest leniwy, więc czy mogę traktować go dokładnie tak samo, jak funkcję generatora, czy też muszę na coś uważać?


1
Przypuszczam, że chcesz zwiększyć i w veryBigHello.
robert

@robert: jeśli się nie mylę, automatycznie wzrasta
the_drow

@the_drow Nie w veryBigHellosamej funkcji.
Will McCutchen

1
@Will: Och, prawda. Ale to tylko czepianie się. To jest przykład. Naprawiono mimo wszystko.
the_drow

Odpowiedzi:


103

To jest leniwe. Dość łatwo udowodnić, że tak jest:

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

Czy to Python 2 czy 3 (lub oba)? Czy w obu jest leniwy? Testowałem na Pythonie 2 i jest leniwy.
becko

2
Przetestowałem to na Pythonie 3.5.2 i ocenia się leniwie.
gobernador

42

To jeszcze łatwiejsze do stwierdzenia niż którakolwiek z poprzednich sugestii:

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

Jeśli enumerate nie przeprowadzi leniwej oceny, zwróci [(0,'a'), (1,'b'), (2,'c')]lub jakiś (prawie) odpowiednik.

Oczywiście enumerate to naprawdę fantazyjny generator:

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
Dzięki za to wyjaśnienie. Miałem trochę trudności ze znalezieniem akceptowanej odpowiedzi. Przynajmniej dopóki nie zobaczę twojego.
trendsetter37

13

Ponieważ można wywołać tę funkcję bez wychodzenia z pamięci, jest ona zdecydowanie leniwa

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

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

0

Oldschoolowa alternatywa, ponieważ korzystałem z generatora, który ktoś inny (sklearn) napisał, a który nie działał z opisanymi tu podejściami.

i=(-1)
for x in some_generator:
    i+=1
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.