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?

Adam
quelle
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
Dave Webb
quelle
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
Wayne Werner
quelle
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
Nikolaus Gradwohl
quelle
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
HashRocketSyntax
quelle