如何克隆Python生成器对象?

Pau*_*tas 52 python clone generator object

考虑这种情况:

#!/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)

我知道这个例子有点多余,但您应该考虑我们需要walk多次使用相同的数据.我有一个基准测试场景,必须使用相同的walk数据才能获得有用的结果.

我试图walk2 = walk在第二次迭代中克隆并使用,但它没有用.问题是......我怎么能复制它?它有可能吗?

先感谢您.

Sve*_*ach 68

你可以使用itertools.tee():

walk, walk2 = itertools.tee(walk)
Run Code Online (Sandbox Code Playgroud)

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

  • 此外,[documentation](http://docs.python.org/2/library/itertools.html#itertools.tee)说:"通常,如果一个迭代器在另一个迭代器启动之前使用大部分或全部数据,使用`list()`而不是`tee()`会更快." 鉴于OP的原始代码片段完全迭代一次,然后再次,不建议他使用`list()`? (8认同)
  • 老兄,这不会复制生成器,而是将其转换为迭代器……这不是生成器。假设我有一个生成器,它可以从包含 60 亿行的 sql 表中部分获取数据,并按顺序... (4认同)

sha*_*ang 14

如果您知道要为每次使用迭代整个生成器,那么通过将生成器展开到列表并多次使用列表,您可能会获得最佳性能.

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


S.L*_*ott 6

定义一个函数

 def walk_home():
     for r in os.walk('/home'):
         yield r
Run Code Online (Sandbox Code Playgroud)

甚至这个

def walk_home():
    return os.walk('/home')
Run Code Online (Sandbox Code Playgroud)

两者都是这样使用的:

for root, dirs, files in walk_home():
    for pathname in dirs+files:
        print os.path.join(root, pathname)
Run Code Online (Sandbox Code Playgroud)

  • 虽然不是 OP 提出的确切问题的答案,但这是一种无需将完整目录树存储在内存中的好方法。+1 (3认同)

Rob*_*xal 5

这是functools.partial() 创建快速生成器工厂的好用例:

from functools import partial
import os

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

walk1, walk2, walk3 = walk_factory(), walk_factory(), walk_factory()
Run Code Online (Sandbox Code Playgroud)

什么functools.partial()是很难用人类语言来描述的,但这就是它的用途。

它在不执行该函数的情况下部分填写了函数参数。因此,它充当函数/生成器工厂。