在python中:使用带有'with'关键字的文件路径列表

时间:2013-07-16 19:14:00

标签: python

如果我想使用两个文件,我可以写:

with open(fname1, 'r') as f1, open(fname2, 'r') as f2:
    # do stuff with f1 and f2

但是如果我有一个路径列表(例如,来自glob.glob)怎么办?我可以在列表理解中做类似的事情吗?我想到的是:

with [open(path, 'r') for path in paths_list] as flist:
    # do stuff with this list of open file objects

如上所述,这不起作用。

3 个答案:

答案 0 :(得分:8)

with语句的对象必须是上下文管理器。所以,不,你不能用列表来做这件事,但你可以用自定义容器来做。

请参阅:http://docs.python.org/2/library/contextlib.html

或者,对于3.3+,这是:http://docs.python.org/dev/library/contextlib.html#contextlib.ExitStack(注意,根据arbarnert的回答,这可以在2.7中使用,使用contextlib2。请参阅他的链接答案。)

这里的实际解决方案可能是如果您不打算使用contextlib2将上下文管理器置于循环中:

for path in paths_list:
    with open(path, 'r') as f:
         #whatever
         pass

编辑:显然,上面会一次打开一个文件。用户需要保持一定数量的文件不会立即打开。

编辑:要同时打开多个文件,ExitStack是您正在寻找的解决方案。

答案 1 :(得分:6)

在3.3+中,ExitStack绝对是答案;事实上,这是文档中给出的第一个例子:

with ExitStack() as stack:
    files = [stack.enter_context(open(path) for path in path_list]
    for f in files:
        do_something(f)

当然,如果您的with正文只是files的循环,那么没有理由这样做 - 只需为循环内的每个文件添加with语句。 (事实上​​,有一个很好的理由这样做 - 为什么一次打开一个可能无限数量的文件句柄只是为了一次使用它们?)但是可能你的真实代码需要使用多个文件同时存在。


在早期版本中,您可以轻松地从3.3 source借用ExitStack。向后移植到3.2是微不足道的;对于2.7,你需要删除(或重写,如果你需要的话)通过异常传播获得花哨的东西,以保证你正确的异常情况,但这很容易。

然而,一个更好的解决方案可能是安装contextlib2关闭PyPI,它“将标准库的contextlib模块的最新版本中的功能提供给早期的Python版本。”然后,您可以使用contextlib2.ExitStack代替contextlib.ExitStack。 (事实上​​,contextlib2在其初步名称ExitStack下有ContextStack,在Python 3.3之前就已经... {/ p>


但是你也可以轻松地构建一个closing_all上下文管理器,类似于stdlib的closing但是有很多东西:

@contextlib.contextmanager
def closing_all(things):
    try:
        yield things
    finally:
        for thing in things:
            thing.close()

如果您需要处理close方法可以引发的事情,您需要更聪明一点 - 但是对于文件对象,以及您与closing一起使用的大多数其他类型,不需要那个。

更大的问题是,如果任何open可以引发异常,则很难找到任何可以作为things参数实际传递的有效序列。但如果这不是问题,使用它甚至比ExitStack更简单:

with closing_all(open(path) for path in path_list) as files:
    for f in fs:
        do_something(f)

您还可以为opening_all(paths, mode='r')构建一个open,并将其包裹在closing_all中,但我认为这不会增加太多。

当然,如果您经常需要这样做,最好的答案是围绕opening_all建立ExitStack,甚至不用closing_all

答案 2 :(得分:2)

您可以使用fileinput

import fileinput

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