【发布时间】:2013-04-12 07:54:28
【问题描述】:
我想将许多文件视为一个文件。将 [filenames] => [file objects] => [lines] 与生成器/不将整个文件读入内存的正确 pythonic 方式是什么?
我们都知道打开文件的正确方法:
with open("auth.log", "rb") as f:
print sum(f.readlines())
而且我们知道将多个迭代器/生成器链接成一个长的一个的正确方法:
>>> list(itertools.chain(range(3), range(3)))
[0, 1, 2, 0, 1, 2]
但是如何将多个文件链接在一起并保留上下文管理器?
with open("auth.log", "rb") as f0:
with open("auth.log.1", "rb") as f1:
for line in itertools.chain(f0, f1):
do_stuff_with(line)
# f1 is now closed
# f0 is now closed
# gross
我可以忽略上下文管理器并做这样的事情,但感觉不对:
files = itertools.chain(*(open(f, "rb") for f in file_names))
for line in files:
do_stuff_with(line)
或者这就是Async IO - PEP 3156 的用途,我只需要稍后等待优雅的语法吗?
【问题讨论】:
-
还要注意
files = itertools.chain(*(open(f, "rb") for f in file_names))在这种情况下肯定不好。解压缩元组会导致在您实际进入chain构造函数之前打开所有文件。使用itertools.chain.from_iterable(open(fname,'r') for fname in filenames))会更好——事实上,这是from_iterable类方法首先需要存在的一个经典原因:)。 -
@mgilson 不知道
from_iterable是个东西!我很高兴我的用例是一个教科书示例,说明它为什么有用。我试图弄清楚如何在没有嵌套 for 循环的情况下正确地让惰性求值工作。谢谢! -
请注意,即使
from_iterable也不能保证在您完成迭代后所有文件都已关闭,因为您永远不知道__del__何时实际运行(尽管我很确定他们会在 Cpython 中)... -
contextlib.ExitStack允许将多个上下文管理器视为一个(在您的情况下不需要,但在相关情况下可能有用)。
标签: python file parsing logging