enumerate () - Generieren eines Generators in Python


87

Ich möchte wissen, was passiert, wenn ich das Ergebnis einer Generatorfunktion an pythons enumerate () übergebe. Beispiel:

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

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

Wird die Aufzählung träge wiederholt oder schlürft sie alles in die erste? Ich bin mir zu 99,999% sicher, dass es faul ist. Kann ich es also genauso behandeln wie die Generatorfunktion, oder muss ich auf irgendetwas achten?


1
Ich nehme an, Sie wollen i in veryBigHello erhöhen.
Robert

@ Robert: Wenn ich mich nicht irre, wird ich automatisch erhöht
the_drow

@the_drow Nicht in der veryBigHelloFunktion selbst.
Will McCutchen

1
@ Will: Oh, richtig. Aber das ist nur ein Trottel. Es ist ein Beispiel. Trotzdem behoben.
the_drow

Antworten:


102

Es ist faul. Es ist ziemlich einfach zu beweisen, dass dies der Fall ist:

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

Ist das Python 2 oder 3 (oder beides)? Ist es in beiden faul? Ich habe auf Python 2 getestet und es ist faul.
Becko

2
Ich habe dies auf Python 3.5.2 getestet und es wird träge ausgewertet.
Gobernador

42

Es ist noch einfacher zu sagen, als es die vorherigen Vorschläge vermuten lassen:

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

Wenn die Aufzählung keine verzögerte Auswertung durchführen würde, würde sie zurückkehren [(0,'a'), (1,'b'), (2,'c')]oder eine (fast) äquivalente.

Aufzählung ist natürlich nur ein ausgefallener 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
Danke für diese Erklärung. Es fiel mir ein bisschen schwer, die akzeptierte Antwort herauszufinden. Zumindest bis ich deine gesehen habe.
Trendsetter37

13

Da Sie diese Funktion aufrufen können, ohne dass Speicherausnahmen auftreten, ist sie definitiv faul

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

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

0

Old-School-Alternative, da ich einen Generator verwendet habe, den jemand anderes (sklearn) geschrieben hat und der mit den Ansätzen hier nicht funktioniert hat.

i=(-1)
for x in some_generator:
    i+=1
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.