파이썬에서 두 생성기를 결합하는 방법?


187

다음 코드를 변경하고 싶습니다

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

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

이 코드로 :

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

오류가 발생합니다.

+ : 'generator'및 'generator'에 대해 지원되지 않는 피연산자 유형

파이썬에서 두 생성기를 결합하는 방법?


1
또한 파이썬이 이런 식으로 작동하기를 원합니다. 정확히 같은 오류가 발생했습니다!
Adam Kurkiewicz

답변:


236

itertools.chain()해야 한다고 생각 합니다.


5
의 반환 값은 인스턴스를 itertools.chain()반환하지 않습니다 types.GeneratorType. 정확한 유형이 중요한 경우를 대비하여.
리가

1
당신은 또한 잘 작동 된 예제를 작성하지 않습니까?
찰리 파커

75

코드 예 :

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

10
이 예를 기존의 고도로 찬성 된 itertools.chain()답변에 추가하지 않겠습니까?
Jean-François Corbett

51

Python (3.5 이상)에서는 다음을 수행 할 수 있습니다.

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

7
너무 많은 pythonic.
Ramazan Polat

9
더 일반적 : def chain(*iterables): for iterable in iterables: yield from iterable( deffor실행할 때 별도의 줄에 넣 습니다.)
wjandrea

모든로부터인가 에서 아무것도하기 전에 굴복 b는 굴복하거나 그들이 교대되고있다?
problemofficer

@problemofficer Yup. 만 a모든 것이 그것으로부터 산출 될 때까지 경우에도 체크 b반복자 없습니다. 는 TypeError대한 b없다는 반복자는 나중에 올 것이다.
GeeTransit

36

간단한 예 :

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

3
이 예를 기존의 고도로 찬성 된 itertools.chain()답변에 추가하지 않겠습니까?
Jean-François Corbett

itertools.chain제너레이터가 아닌 반복자를 반환하기 때문에 이것은 옳지 않습니다.
David J.

그냥 할 수 없어 chain([1, 2, 3], [3, 4, 5])?
코먼

10

itertools.chain.from_iterable을 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

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)

불필요한 목록 이해를 사용하고 있습니다. genny이미 생성기를 반환 할 때 불필요한 생성기 표현식을 사용하고 있습니다. list(itertools.chain.from_iterable(genny(x)))훨씬 간결합니다.
Corman

! ist 이해는 질문에 따라 두 생성기를 만드는 쉬운 방법이었습니다. 어쩌면 내 대답은 그 점에서 약간 복잡합니다.
앤드류 페이트

기존 답변 에이 답변을 추가 한 이유는 많은 발전기가있는 사람들을 도울 수 있기 때문입니다.
앤드류 페이트

쉬운 방법은 아니지만 많은 쉬운 방법이 있습니다. 기존 생성기에서 생성기 표현식을 사용하면 성능이 저하되고 list생성자는 목록 이해력보다 훨씬 읽기 쉽습니다. 당신의 방법은 그 점에서 훨씬 더 읽을 수 없습니다.
코만

Corman, 목록 생성자가 실제로 더 읽기 쉽다는 것에 동의합니다. 그래도 '여러 가지 쉬운 방법'을 보는 것이 좋을 것입니다 ... 위의 wjandrea의 의견은 itertools.chain.from_iterable과 동일한 것으로 보이는 것으로 생각합니다.
앤드류 페이트

8

여기 에 중첩 된 s 와 함께 생성기 표현식 을 사용하고 있습니다 for.

a = range(3)
b = range(5)
ab = (i for it in (a, b) for i in it)
assert list(ab) == [0, 1, 2, 0, 1, 2, 3, 4]

2
약간의 설명은 아프지 않을 것입니다.
Ramazan Polat

글쎄, 나는 파이썬의 문서보다 이것을 더 잘 설명 할 수 있다고 생각하지 않는다.
Alexey

(제너레이터 표현식에 대한 문서는 답변과 연결되어 있습니다. 문서를 내 답변에 복사하여 붙여 넣을 이유는 없습니다.)
Alexey

3

unpack 연산자를 사용할 수도 있습니다 *.

concat = (*gen1(), *gen2())

참고 : '비 지연'반복에 가장 효율적으로 작동합니다. 다른 종류의 이해와 함께 사용할 수도 있습니다. 생성기 연결에 선호되는 방법은 @Uduse 의 답변입니다 .


1

생성기를 개별적으로 유지하면서 동시에 반복적으로 반복하려면 zip ()을 사용할 수 있습니다.

참고 : 두 발전기 중 짧은 쪽에서 반복이 중지됩니다.

예를 들면 다음과 같습니다.

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

제너레이터 (gen1과 gen 2)를 사용해야하며 둘 다의 결과가 필요한 추가 계산을 수행하려고합니다. map 함수를 통해 이러한 함수 / 계산 결과를 반환 할 수 있으며, 결과적으로 루프를 생성 할 수있는 생성기를 반환합니다.

이 시나리오에서는 함수 / 계산을 람다 함수를 통해 구현해야합니다. 까다로운 부분은 맵과 람다 함수 내에서 수행하려는 작업입니다.

제안 된 솔루션의 일반적인 형태 :

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

0

모든 복잡한 솔루션 ...

그냥 해:

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

두 생성기를 모두 "결합"하려면 다음을 수행하십시오.

for directory, dirs, files in 
        [x for osw in [os.walk(director_1), os.walk(director_2)] 
               for x in osw]:
    do_something()

0

사용자 "wjandrea"의 의견에서 제안한 것처럼 가장 좋은 해결책은 다음과 같습니다.

def concat_generators(*args):
    for gen in args:
        yield from gen

반환 된 유형을 변경하지 않으며 실제로는 pythonic입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.