我想更改下面的代码

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'的操作数类型

如何在Python中连接两个生成器?


当前回答

假设我们有两个生成器(第1代和第2代),我们想要执行一些额外的计算,需要这两个生成器的结果。 我们可以通过map方法返回这种函数/计算的结果,该方法反过来返回一个生成器,我们可以循环使用它。

在这种情况下,函数/计算需要通过lambda函数实现。 棘手的部分是我们打算在映射及其lambda函数中做什么。

建议解决方案的一般形式:

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

其他回答

您可以将任何生成器放入列表中。虽然不能组合生成器,但可以组合列表。这样做的缺点是实际上在内存中创建了3个列表,但优点是可读性非常好,不需要导入,并且是单行习惯用法。

OP解决方案。

for directory, dirs, files in list(os.walk(directory_1)) + list(os.walk(directory_2)):
    do_something()
a = range(20)
b = range(10,99,3)
for v in list(a) + list(b):
    print(v) 

Itertools.chain()应该做到这一点。它接受多个可迭代对象,并逐个产生结果,大致相当于:

def chain(*iterables):
    for it in iterables:
        for element in it:
            yield element

使用的例子:

from itertools import chain

g = (c for c in 'ABC')  # Dummy generator, just for example
c = chain(g, 'DEF')  # Chain the generator and a string
for item in c:
    print(item)

输出:

A
B
C
D
E
F

(免责声明:仅限Python 3 !)

与你想要的语法相似的是使用splat操作符展开两个生成器:

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

解释:

这有效地执行了将两个生成器的单层扁平化为3元组的n元组(来自os.walk),如下所示:

((directory1, dirs1, files1), (directory2, dirs2, files2), ...)

然后for循环遍历这个n元组。

当然,通过简单地用括号替换外括号,你可以得到一个3元组的列表,而不是3元组的n元组:

for directory, dirs, files in [*os.walk(directory_1), *os.walk(directory_2)]:
    do_something()

结果如下:

[(directory1, dirs1, files1), (directory2, dirs2, files2), ...]

Pro:

这种方法的优点是不需要导入任何东西,也不需要大量代码。

Con:

缺点是将两个生成器转储到一个集合中,然后遍历该集合,有效地进行了两次传递,可能会使用大量内存。

假设我们有两个生成器(第1代和第2代),我们想要执行一些额外的计算,需要这两个生成器的结果。 我们可以通过map方法返回这种函数/计算的结果,该方法反过来返回一个生成器,我们可以循环使用它。

在这种情况下,函数/计算需要通过lambda函数实现。 棘手的部分是我们打算在映射及其lambda函数中做什么。

建议解决方案的一般形式:

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

2020年更新:在Python 3和Python 2中都可以工作

import itertools

iterA = range(10,15)
iterB = range(15,20)
iterC = range(20,25)

第一个选项

for i in itertools.chain(iterA, iterB, iterC):
    print(i)

# 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

可选选项,在python 2.6中引入

for i in itertools.chain.from_iterable( [iterA, iterB, iterC] ):
    print(i)

# 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Itertools.chain()是基本的。

Itertools.chain.from_iterable()很方便,如果你有一个包含可迭代对象的可迭代对象。例如,每个子目录的文件列表,如[["src/server.py", "src/readme.txt"], ["test/test.py"]]]。