如何克隆一个Python生成器对象?

考虑这种情况:

  #!/ usr / bin / env python
 # -  *  - 编码:utf-8  -  *  - 
import操作系统

 walk = os.walk('/ home')

为根,目录,文件在步行:
    对于dirs +文件中的path名:
        打印os.path.join(根,path名)

为根,目录,文件在步行:
    对于dirs +文件中的path名:
        打印os.path.join(根,path名) 

我知道这个例子有点多余,但是你应该考虑到我们需要多次使用相同的walk数据。 我有一个基准场景,使用相同的walk数据是强制性的,以获得有用的结果。

我已经尝试了walk2 = walk来克隆和使用在第二次迭代,但它没有奏效。 问题是…我可以如何复制它? 有没有可能?

先谢谢你。

你可以使用itertools.tee()

 walk, walk2 = itertools.tee(walk) 

请注意,这可能“需要大量额外的存储”,正如文档指出的那样。

如果你知道你将遍历整个生成器的每一个用法,你可能会得到最好的性能,展开生成器到列表和多次使用列表。

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

定义一个函数

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

甚至这个

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

两者都是这样使用的:

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

这个答案旨在扩大/阐述其他答案所expression的内容。 解决scheme将根据您的目标实现而定。

如果你想多次遍历os.walk的完全相同的结果,你将需要从os.walk迭代的项目(即walk = list(os.walk(path)) )初始化一个列表。

如果您必须保证数据保持不变,那么这可能是您唯一的select。 但是,有几种情况是不可能或不可取的。

  1. 如果输出的大小足够大(即试图list()整个文件系统可能会冻结你的计算机),将不可能list()一个迭代器。
  2. 如果希望在每次使用之前获取“新鲜”数据,则list()可迭代是不可取的。

list()不适合的情况下,您将需要按需运行您的generator。 请注意,发电机每次使用后都会熄灭,因此会造成轻微的问题。 为了多次“重新运行”您的发电机,您可以使用以下模式:

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

前面提到的devise模式将允许您保持代码干爽。