2010-07-09 14 views
99

quiero cambiar el código siguiente¿Cómo unir dos generadores en Python?

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

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

a este código:

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

me sale el error:

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

Cómo unir dos generadores en Python?

+1

También me gustaría Python para trabajar de esta manera. ¡Obtuve exactamente el mismo error! –

Respuesta

141

Creo que itertools.chain() debería hacerlo.

+1

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

+3

sí, esto es exactamente lo que 'chain()' es para –

+16

Cuando se usa 'itertools.chain' para concatenar no dos iterables, como en la pregunta, sino todos los iterables en un iterable (por ejemplo, 'chain (* imap (xrange, xrange (5)))'), es posible que se encuentre con [Python bug # 4806] (http://bugs.python.org/issue4806), que enmascara cualquier TypeError generado dentro de la iterable y conduce a un mensaje de error confuso. Alternativamente, puede usar 'itertools.chain.from_iterable' (desde Python 2.6) en ese caso, que toma directamente el iterable de iterables como argumento:' chain.from_iterable (imap (xrange, xrange (5))) '. –

29

Un ejemplo de código:

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 que puede hacer cosas como:

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

ejemplo simple:

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

Si desea mantener los generadores se separan pero aún se repiten sobre ellos al mismo tiempo que puede usar zip():

NOTA: La iteración se detiene en el más corto de los dos generadores

Por ejemplo:

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

supongamos que tenemos a los generadores (Gen1 y Gen 2) y queremos realizar algún cálculo adicional que requiere el resultado de ambos. Podemos devolver el resultado de dicha función/cálculo a través del método de mapa, que a su vez devuelve un generador que podemos enlazar.

En este escenario, la función/cálculo debe implementarse a través de la función lambda. La parte difícil es lo que pretendemos hacer dentro del mapa y su función lambda.

forma general de la solución propuesta:

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

Debería considerar publicar alguna explicación útil de lo que hace en lugar de solo el bloque de código – AK47

1

En python3 + que puede hacer:

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