2012-06-25 9 views
20

Ho una funzione che produce risultati mentre vengono scaricati. Ai fini di questa domanda, consente di dire io cedo una puntura ogni secondo ma voglio una funzione convenienza per avvolgere il mio generatore:Come posso ottenere risultati da una funzione di generatore Python annidata?

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 

... perché non fa che basta stampare le 5 corde Sono aspettando? Invece sembra restituire il functio generatore:

<generator object GeneratorFunction at 0x020649B8> 

Come posso ottenere questo per cedere le corde come una normale funzione di generatore sarebbe?

+7

proposito, in Python 3.3, 'resa da GeneratorFunction (3)' funzionerà .. – DSM

+0

@DSM: Grazie . Ancora non è ancora passata la transizione a 3+ ... –

risposta

33

SmallGenerator bisogno di essere qualcosa intorno:

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

Nell'implementazione SmallGenerator produce un generatore reale, non le voci generate da esso .

+0

Ecco perché la risposta che ho postato funziona? Perché restituisce un generatore invece di cederne uno? –

+0

@JonCage Sì. La mia spiegazione è in realtà sbagliata. Volevo dire "rendimenti" piuttosto che "ritorni". Lo modifico. Il ritorno del generatore stesso funziona (come nella risposta). Tuttavia, quando si esegue il wrapping di un generatore, si desidera applicare una sorta di funzione su ciascun elemento che genererebbe. –

+0

@loan: Sì, lo vedo ora - grazie per la spiegazione. Restituire la funzione del generatore anziché il ciclo e restituire ogni risultato una seconda volta sarebbe più veloce? –

15

Non posso credere di aver perso questo; La risposta è quello di restituire semplicemente la funzione di generatore con argomenti adatti applicata:

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

Potrebbe essere necessario utilizzare new yield from, disponibile da Python 3.3, noto come "delegated generator".

Se ho compreso correttamente la domanda, sono giunto allo stesso problema e ho trovato una risposta altrove.

ho voluto fare qualcosa di simile:

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 

Io uso questo, invece:

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

ho avuto la risposta da questa pagina: Python 3: Using "yield from" in Generators - Part 1 (simeonvisser.com).

1

Sono venuto qui cercando una forma diversa di "resa annidata" e alla fine ho trovato la risposta nascosta. Potrebbe non essere il migliore ma funziona.

Volevo cedere attraverso un albero del registro e qui è la soluzione.

 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

Ecco un altro piccolo esempio per generare la tabella di moltiplicazione da 1 a 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() 
Problemi correlati