2010-07-09 5 views
99

Chcę zmienić następujący kodJak połączyć dwa generatory w Pythonie?

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

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

do tego kodu:

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

pojawia się błąd:

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

Jak połączyć dwa generatory w Pythonie?

+1

Chciałbym również jak Python pracować w ten sposób. Mam dokładnie ten sam błąd! –

Odpowiedz

141

Myślę, że powinien to zrobić itertools.chain().

+1

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

+3

tak, to jest dokładnie to, co 'chain()' jest dla –

+16

Gdy używasz 'itertools.chain' do łączenia dwóch iteracji, jak w pytaniu, ale wszystkie iterable w iterable (np. 'chain (* imap (xrange, xrange (5)))), możesz natknąć się na [Python bug # 4806] (http://bugs.python.org/issue4806), który maskuje każdy TypeError wywołany w iterable i prowadzi do mylącego komunikatu o błędzie. Możesz też użyć 'itertools.chrom.from_iterable' (od Pythona 2.6), który bezpośrednio bierze iterable iterables jako argument:' chain.from_iterable (imap (xrange, xrange (5))) '. –

29

przykładu kodu:

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

Z itertools.chain.from_iterable można robić takie rzeczy jak:

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

Prosty przykład:

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

Jeśli chcesz zachować generatory są oddzielne, ale wciąż powtarzają je w tym samym czasie, co możesz użyć zip():

UWAGA: Iteracja zatrzymuje się przez krótszy z dwóch generatorów

Na przykład:

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

Powiedzmy, że mamy do generatorów (Gen 1 i Gen 2) i chcemy wykonać jakieś dodatkowe obliczenia, które wymaga wyniku obu. Możemy zwrócić wynik takiej funkcji/obliczenia za pomocą metody mapy, która z kolei zwraca generator, który możemy uruchomić.

W tym scenariuszu funkcja/obliczenia muszą zostać zaimplementowane za pomocą funkcji lambda. Podstępna część jest tym, co chcemy zrobić na mapie i jej funkcji lambda.

Ogólne forma proponowanego rozwiązania:

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

Powinieneś rozważyć umieszczenie jakiegoś przydatnego wyjaśnienia, co to robi zamiast tylko bloku kodu – AK47

1

W Python3 + można zrobić:

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