在多个文件的所有行上迭代的最python方法是什么?

2024-04-26 12:03:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我想把许多文件当作一个文件来处理。使用生成器[文件名]=>;[文件对象]=>;[行]而不是将整个文件读入内存,正确的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的用途,我以后就只能等待优雅的语法了?


Tags: 文件方法ingtauthchainforas
1条回答
网友
1楼 · 发布于 2024-04-26 12:03:29

总是有^{}

for line in fileinput.input(filenames):
    ...

然而,读取source时,似乎fileinput.FileInput不能用作上下文管理器1。要解决这个问题,可以使用^{},因为FileInput实例有一个合理实现的close方法:

from contextlib import closing
with closing(fileinput.input(filenames)) as line_iter:
    for line in line_iter:
        ...

上下文管理器的另一种选择是在文件上编写一个简单的函数循环,并在运行时生成行:

def fileinput(files):
    for f in files:
        with open(f,'r') as fin:
            for line in fin:
                yield line

在这里我不需要itertools.chain。。。这里的魔力在yield语句中,该语句用于将普通函数转换为一个非常懒的生成器。


作为旁白,从python3.2开始,fileinput.FileInput被实现为一个上下文管理器,它与我们之前使用的contextlib完全一样。现在我们的例子变成:

# Python 3.2+ version
with fileinput.input(filenames) as line_iter:
    for line in line_iter:
        ...

尽管另一个例子也适用于python3.2+。

相关问题 更多 >