考虑这种情况:
#!/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
克隆并在第二次迭代中使用,但它没有用。问题是......我怎么能复制它?它有可能吗?
提前谢谢。
答案 0 :(得分:66)
答案 1 :(得分:14)
如果你知道你将为每次使用迭代整个生成器,你可能会通过将生成器展开到列表并多次使用列表来获得最佳性能。
walk = list(os.walk('/home'))
答案 2 :(得分:4)
定义一个函数
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)
答案 3 :(得分:2)
这是functools.partial()
的好用例
建立快速的发电机工厂:
--hot
from functools import partial
import os
walk_factory = partial(os.walk, '/home')
walk1, walk2, walk3 = walk_factory(), walk_factory(), walk_factory()
的作用很难用人类的语言来形容,但这是它的作用。
它部分填写功能参数,而不执行该功能。因此,它充当了函数/生成器工厂。
答案 4 :(得分:1)
这个答案旨在扩展/阐述其他答案所表达的内容。解决方案必然会根据您希望实现的完全而变化。
如果要多次迭代os.walk
的完全相同的结果,则需要从os.walk
iterable的项目(即walk = list(os.walk(path))
)初始化列表。
如果您必须保证数据保持不变,那么这可能是您唯一的选择。但是,有几种情况是不可能或不可取的。
list()
,则list()
不可能(即尝试list()
整个文件系统可能会冻结您的计算机。)list()
是不可取的。如果#!/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
不合适,您需要按需运行生成器。请注意,每次使用后发电机都会熄灭,因此这会产生轻微问题。为了多次“重新运行”您的生成器,您可以使用以下模式:
SSH -L 3307:mysql:3306 <server_name>
上述设计模式将允许您将代码保持干净。
答案 5 :(得分:0)
此“ Python生成器侦听器”代码可让您在单个生成器上拥有多个侦听器,例如os.walk
,甚至以后还会有人“鸣叫”。
def walkme(): os.walk('/ home')
m1 =混合器(walkme) m2 = Muxer(walkme)
然后m1和m2甚至可以在线程中运行,并且可以随意处理。
请参阅:https://gist.github.com/earonesty/cafa4626a2def6766acf5098331157b3
import queue
from threading import Lock
from collections import namedtuple
class Muxer():
Entry = namedtuple('Entry', 'genref listeners, lock')
already = {}
top_lock = Lock()
def __init__(self, func, restart=False):
self.restart = restart
self.func = func
self.queue = queue.Queue()
with self.top_lock:
if func not in self.already:
self.already[func] = self.Entry([func()], [], Lock())
ent = self.already[func]
self.genref = ent.genref
self.lock = ent.lock
self.listeners = ent.listeners
self.listeners.append(self)
def __iter__(self):
return self
def __next__(self):
try:
e = self.queue.get_nowait()
except queue.Empty:
with self.lock:
try:
e = self.queue.get_nowait()
except queue.Empty:
try:
e = next(self.genref[0])
for other in self.listeners:
if not other is self:
other.queue.put(e)
except StopIteration:
if self.restart:
self.genref[0] = self.func()
raise
return e
def __del__(self):
with self.top_lock:
try:
self.listeners.remove(self)
except ValueError:
pass
if not self.listeners and self.func in self.already:
del self.already[self.func]