Python如何迭代处理多个文件,而不使用显式的for循环?

3

我有一个脚本,使用大段文本来训练模型。目前它的写法是要么从文件中读取,要么从标准输入中读取。

parser.add_argument('-i', help='input_file', default=sys.stdin)
... # do a bunch of other stuff
if args.i is sys.stdin:
    m.train(args.i)
else:
    m.train(open(args.i, 'r'))

然后我可以这样调用我的脚本:
python myscript.py -i trainingdata.txt

或者
cat trainingdata.txt | python myscript.py

第二个版本特别适用于我想要搜索文件系统并使用多个文件来训练模型的情况。但是,如果我同时尝试使用进行性能分析,由于管道的原因,这可能变得棘手。
python -m cProfile myscript.py ... 

我知道可以使用-i选项发送多个文件,并迭代处理这些文件, 但是这样会需要更改train()方法的行为以避免覆盖数据。
有没有一种好的方法来打开IO通道,简单说就是能够连接输入,而不用显式地逐行读取和写入呢?

我觉得你可能想要研究一下Pandas。 - mauve
@mauve,我已经在这个项目中使用了Pandas,你具体指的是什么? - posdef
我认为这将有助于“不逐行阅读”的部分。我有一些代码,其中我打开目录中的每个文件,将其读入数据框中,连接数据框,按时间排序,并以csv格式输出为10小时块。 - mauve
fileinput 模块非常擅长将作为参数和可选标准输入的文件连接起来。也许你应该看一下它... - Serge Ballesta
如果我理解正确的话,它与 argparse 不兼容,而 argparse 在我的情况下是必要的。我有多个不同的 CL 参数需要处理。但无论如何,这是一个好建议,我会尽量记住它。 - posdef
1个回答

2
你可以使用生成器(yield)打开文件并从文件名中返回打开的文件:chain
from itertools import chain

def yield_open(filenames):
    for filename in filenames:
        with open(filename, 'r') as file:
            yield file

def train(file):
    for line in file:
        print(line, end='')
    print()

files = chain.from_iterable(yield_open(filenames=['file1.txt', 'file2.txt']))
train(files)

这样做的好处是每次只需打开一个文件。您还可以将其用作“数据管道”(可能更易读):
file_gen = yield_open(filenames=['file1.txt', 'file2.txt'])
files = chain.from_iterable(file_gen)
train(files)

有趣的是,这应该模仿管道“cat”命令的行为.. 有没有更通用的方法来编写with语句以处理任意(可能很多)数量的文件? - posdef
@posdef 尝试做到了。这是你想要的吗? - hiro protagonist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接