2010-07-09 16 views
99

Voglio cambiare il seguente codiceCome unire due generatori in Python?

for directory, dirs, files in os.walk(directory_1): 
    do_something() 

for directory, dirs, files in os.walk(directory_2): 
    do_something() 

a questo codice:

for directory, dirs, files in os.walk(directory_1) + os.walk(directory_2): 
    do_something() 

ottengo l'errore:

unsupported operand type(s) for +: 'generator' and 'generator'

Come unire due generatori in Python?

+1

Mi piacerebbe anche Python per lavorare in questo modo. Hai esattamente lo stesso errore! –

risposta

141

Penso che itertools.chain() dovrebbe farlo.

+1

http://docs.python.org/library/itertools.html – reto

+3

sì, questo è esattamente ciò che 'chain()' è per –

+16

Quando si utilizza 'itertools.chain' per concatenare non due iterabili, come nella domanda, ma tutti i iterabili in un iterabile (ad esempio, 'chain (* imap (xrange, xrange (5)))'), potresti imbatterti in [Python bug # 4806] (http://bugs.python.org/issue4806), che maschera qualsiasi errore TypeError all'interno del file iterable e porta a un messaggio di errore confuso. In alternativa, puoi usare 'itertools.chain.from_iterable' (dal Python 2.6) in quel caso, che prende direttamente l'iterabile di iterables come argomento:' chain.from_iterable (imap (xrange, xrange (5))) '. –

29

Un esempio di codice:

from itertools import chain 

def generator1(): 
    for item in 'abcdef': 
     yield item 

def generator2(): 
    for item in '123456': 
     yield item 

generator3 = chain(generator1(), generator2()) 
for item in generator3: 
    print item 
5

Con itertools.chain.from_iterable si possono fare cose come:

def genny(start): 
    for x in range(start, start+3): 
    yield x 

y = [1, 2] 
ab = [o for o in itertools.chain.from_iterable(genny(x) for x in y)] 
print(ab) 
1

semplice esempio:

from itertools import chain 
x = iter([1,2,3])  #Create Generator Object (listiterator) 
y = iter([3,4,5])  #another one 
result = chain(x, y) #Chained x and y 
0

Se si desidera mantenere i generatori si separano ma continuano a scorrere su di essi allo stesso tempo puoi usare zip():

NOTA: iterazione si ferma al più corto dei due generatori

Ad esempio:

for (root1, dir1, files1), (root2, dir2, files2) in zip(os.walk(path1), os.walk(path2)): 

    for file in files1: 
     #do something with first list of files 

    for file in files2: 
     #do something with second list of files 
0

Diciamo che dobbiamo generatori (Gen1 e Gen 2) e vogliamo eseguire alcuni calcoli in più che richiede il risultato di entrambi. Possiamo restituire il risultato di tale funzione/calcolo attraverso il metodo map, che a sua volta restituisce un generatore su cui possiamo eseguire il looping.

In questo scenario, la funzione/calcolo deve essere implementata tramite la funzione lambda. La parte difficile è ciò che miriamo a fare all'interno della mappa e la sua funzione lambda.

forma generale della soluzione proposta:

def function(gen1,gen2): 
     for item in map(lambda x, y: do_somethin(x,y), gen1, gen2): 
      yield item 
+2

Si dovrebbe prendere in considerazione la pubblicazione di alcune utili spiegazioni su ciò che fa invece del solo blocco di codice – AK47

1

In python3 + si può fare:

def concat(a, b): 
    yield from a 
    yield from b