enumerate () - ing un generador en Python


88

Me gustaría saber qué sucede cuando paso el resultado de una función generadora a enumerate () de python. Ejemplo:

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

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

¿Se repite la enumeración de forma perezosa, o lo engulle todo en la primera? Estoy 99,999% seguro de que es perezoso, así que ¿puedo tratarlo exactamente igual que la función del generador, o debo tener cuidado con algo?


1
Supongo que quieres incrementar i en veryBigHello.
robert

@robert: si no me equivoco, se aumenta automáticamente
the_drow

@the_drow No en la veryBigHellofunción en sí.
Will McCutchen

1
@Will: Oh, correcto. Pero eso es simplemente quisquilloso. Es un ejemplo. Arreglado de todos modos.
the_drow

Respuestas:


103

Es perezoso. Es bastante fácil demostrar que ese es el 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

¿Es este Python 2 o 3 (o ambos)? ¿Es perezoso en ambos? Probé en Python 2 y es vago.
becko

2
Probé esto en Python 3.5.2 y se evalúa de manera perezosa.
gobernador

42

Es incluso más fácil de decir que cualquiera de las sugerencias 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>

Si enumerate no realiza una evaluación perezosa, devolvería [(0,'a'), (1,'b'), (2,'c')]o algo (casi) equivalente.

Por supuesto, enumerate es realmente un generador elegante:

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
Gracias por esta explicacion. Me costó un poco averiguar la respuesta aceptada. Al menos hasta que vi el tuyo.
trendsetter37

13

Como puede llamar a esta función sin salirse de las excepciones de memoria, definitivamente es perezoso

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

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

0

Alternativa de la vieja escuela ya que estaba usando un generador que alguien más (sklearn) escribió que no funcionó con los enfoques aquí.

i=(-1)
for x in some_generator:
    i+=1
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.