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.