如何克隆Python生成器对象?

How to clone a Python generator object?

本方案考虑:P></

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os

walk = os.walk('/home')

for root, dirs, files in walk:
    for pathname in dirs+files:
        print os.path.join(root, pathname)

for root, dirs, files in walk:
    for pathname in dirs+files:
        print os.path.join(root, pathname)

我知道这一点,但你能闭嘴example is that we should,考虑使用walkneed to the same日期超过一次。我在基准情景和使用日期是强制性的walkof same to get帮助的结果。P></

我想walk2 = walkto the second迭代的克隆和使用,但它不挤压。The question is…如何可以复制吗?它曾经是可能的吗?P></

谢谢你提前。P></


您可以使用itertools.tee()

1
walk, walk2 = itertools.tee(walk)

请注意,正如文档所指出的,这可能"需要大量的额外存储"。


如果知道每次使用时都要遍历整个生成器,那么将生成器展开到一个列表并多次使用该列表,可能会获得最佳性能。

walk = list(os.walk('/home'))


定义函数

1
2
3
 def walk_home():
     for r in os.walk('/home'):
         yield r

甚至这个

1
2
def walk_home():
    return os.walk('/home')

两者都是这样使用的:

1
2
3
for root, dirs, files in walk_home():
    for pathname in dirs+files:
        print os.path.join(root, pathname)


这是functools.partial()的一个很好的使用案例。制造快速发电机工厂:

1
2
3
4
5
6
from functools import partial
import os

walk_factory = partial(os.walk, '/home')

walk1, walk2, walk3 = walk_factory(), walk_factory(), walk_factory()

functools.partial()所做的很难用人类语言来描述,但这^正是它的目的。

它部分地填充函数参数而不执行该函数。因此,它充当一个功能/发电机工厂。


此答案旨在扩展/详细说明其他答案所表达的内容。解决方案必然会有所不同,具体取决于您的目标是实现什么。

如果您要多次重复os.walk的完全相同的结果,则需要从os.walkiterable的项(即walk = list(os.walk(path)))初始化一个列表。

如果您必须保证数据保持不变,那可能是您唯一的选择。然而,有几种情况下这是不可能或不可取的。

  • 如果输出的大小足够大(即尝试使用list()文件系统,整个文件系统可能会冻结您的计算机),则不可能使用list()一个iterable。
  • 如果您希望在每次使用之前获得"新"数据,那么list()是不可取的。
  • 如果list()不合适,您需要按需运行发电机。请注意,发电机每次使用后都会熄灭,因此这会造成一个小问题。要多次"重新运行"生成器,可以使用以下模式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import os

    class WalkMaker:
        def __init__(self, path):
            self.path = path
        def __iter__(self):
            for root, dirs, files in os.walk(self.path):
                for pathname in dirs + files:
                    yield os.path.join(root, pathname)

    walk = WalkMaker('/home')

    for path in walk:
        pass

    # do something...

    for path in walk:
        pass

    上述设计模式将允许您保持代码干燥。