2012-06-25 11 views
20

Tengo una función que produce resultados a medida que los descarga. A los efectos de esta pregunta, digamos que producen una picadura de una vez por segundo, pero quiero una función de conveniencia para envolver mi generador:¿Cómo obtengo los resultados de una función de generador de Python anidada?

import time 

def GeneratorFunction(max_val): 
    for i in range(0,5): 
     time.sleep(1) 
     yield "String %d"%i 

def SmallGenerator(): 
    yield GeneratorFunction(3) 

for s in SmallGenerator(): 
    print s 

... ¿por qué no que acaba de imprimir las 5 cuerdas estoy esperando? En su lugar aparece para devolver el generador de funcio:

<generator object GeneratorFunction at 0x020649B8> 

¿Cómo puedo conseguir que esto dió las cuerdas como una función de generador normal sería?

+7

FYI, en Python 3.3, 'rendimiento a partir de GeneratorFunction (3)' trabajará .. – DSM

+0

@DSM: Gracias . Todavía no ha hecho la transición a 3+ aún ... –

Respuesta

33

SmallGenerator tienen que ser algo en torno a:

def SmallGenerator(): 
    for item in GeneratorFunction(3): 
     yield item 

En su aplicación SmallGenerator produce un generador real, no los elementos generados por ella .

+0

¿Entonces por qué la respuesta que publiqué funciona? ¿Porque está devolviendo un generador en vez de ceder uno? –

+0

@JonCage Sí. Mi explicación es realmente incorrecta. Tenía que decir "rendimientos" en lugar de "devoluciones". Voy a editar eso. La devolución del generador en sí funciona (como en su respuesta). Sin embargo, cuando está envolviendo un generador, querrá aplicar algún tipo de función en cada elemento que genere. –

+0

@loan: Sí, ahora lo veo, gracias por la explicación. ¿Sería más rápido devolver la función del generador en lugar de un bucle y producir cada resultado por segunda vez? –

15

No puedo creer que me haya perdido esto; La respuesta es simplemente devolver la función de generador con argumentos adecuados aplicada:

import time 

def GeneratorFunction(max_val): 
    for i in range(0,max_val): 
     time.sleep(1) 
     yield "String %d"%i 

def SmallGenerator(): 
    return GeneratorFunction(3) # <-- note the use of return instead of yield 

for s in SmallGenerator(): 
    print s 
10

Es posible que tenga que utilizar el new yield from, disponible desde Python 3.3, conocido como "delegated generator".

Si entendí la pregunta correctamente, llegué al mismo problema y encontré una respuesta en otro lugar.

que quería hacer algo como esto:

def f(): 

    def g(): 

     do_something() 
     yield x 
     … 
     yield y 

    do_some_other_thing() 
    yield a 
    … 
    g() # Was not working. 
    yield g() # Was not what was expected neither; yielded None. 
    … 
    yield b 

Ahora utilizo este lugar:

yield from g() # Now it works, it yields x and Y. 

Tengo la respuesta de esta página: Python 3: Using "yield from" in Generators - Part 1 (simeonvisser.com).

1

Vine aquí en busca de una forma diferente de "rendimiento anidado" y finalmente encontré la respuesta oculta. Puede que no sea el mejor, pero funciona.

Estaba queriendo ceder a través de un árbol de registro y aquí está la solución.

 def genKeys(key): 
      for value in key.values(): 
       yield value 
      for subkey in key.subkeys(): 
       print(subkey) 
       for x in genKeys(subkey): #this is the trick 
        continue 
0

Aquí hay otro pequeño ejemplo para la generación de la tabla de multiplicar del 1 al 10:

class Gen1: 

    def __init__(self, gen2): 
     self.gen2 = gen2 

    def __iter__(self):  
     for a in range(1, 11):  
      for b in self.gen2: 
       yield a * b 


class Gen2:  

    def __iter__(self): 
     for a in range(1, 11): 
      yield a 


def main(): 

    gen2 = Gen2() 
    gen1 = Gen1(gen2) 

    for v in gen1: 
     print(v) 

if __name__ == '__main__': 
    main() 
Cuestiones relacionadas