如果我想使用两个文件,我可以写:
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
如上所述,这不起作用。
答案 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):
...