如何克隆一个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。 但是,有几种情况是不可能或不可取的。
- 如果输出的大小足够大(即试图
list()
整个文件系统可能会冻结你的计算机),将不可能list()
一个迭代器。 - 如果希望在每次使用之前获取“新鲜”数据,则
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模式将允许您保持代码干爽。