注意:我知道
with open('f1') as f1, open('f2') as f2:
...
语法。 这是一个不同的问题。
给定一个字符串列表
file_names
,有没有一种方法可以使用with
/as
来使用单行打开其中的每个文件名。 例如:
with [open(fn) for fn in file_names] as files:
# use the list of files
这当然不起作用,因为它尝试在列表上使用上下文管理器。 列表的长度可能直到运行时才知道
如果您可以访问Python 3.3+,有一个专门为此目的而设计的特殊类:
ExitStack
。它的工作原理正如您所期望的:
with contextlib.ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
这个怎么样?
class ListContext:
def __init__(self, l):
self.l = l
def __enter__(self):
for x in self.l:
x.__enter__()
return self.l
def __exit__(self, type, value, traceback):
for x in self.l:
x.__exit__(type, value, traceback)
arr = ['a', 'b', 'c']
with ListContext([open(fn, 'w') for fn in arr]) as files:
print files
print files
输出是:
[<open file 'a', mode 'w' at 0x7f43d655e390>, <open file 'b', mode 'w' at 0x7f43d655e420>, <open file 'c', mode 'w' at 0x7f43d655e4b0>]
[<closed file 'a', mode 'w' at 0x7f43d655e390>, <closed file 'b', mode 'w' at 0x7f43d655e420>, <closed file 'c', mode 'w' at 0x7f43d655e4b0>]
注意,它们在上下文中打开,在外部关闭。
这是使用 Python 上下文管理器 API。
编辑:似乎已经存在,但已弃用:请参阅contextlib和这个SO问题。 像这样使用它:
import contextlib
with contextlib.nested(*[open(fn, 'w') for fn in arr]) as files:
print files
print files
contextlib.nested()
,这在 Python 2.7 中已被弃用,支持 with 语句的多管理器形式,但如文档中所述:
与 with 语句的多管理器形式相比,该函数的一个优点是参数解包允许它与可变数量的上下文管理器一起使用
如果您使用的是 Python 3.x,以下是 Python 2.7 源代码:
from contextlib import contextmanager
@contextmanager
def nested(*managers):
"""Combine multiple context managers into a single nested context manager.
This function has been deprecated in favour of the multiple manager form
of the with statement.
The one advantage of this function over the multiple manager form of the
with statement is that argument unpacking allows it to be
used with a variable number of context managers as follows:
with nested(*managers):
do_something()
"""
warn("With-statements now directly support multiple context managers",
DeprecationWarning, 3) exits = []
vars = []
exc = (None, None, None)
try:
for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
exits.append(exit)
yield vars
except:
exc = sys.exc_info()
finally:
while exits:
exit = exits.pop()
try:
if exit(*exc):
exc = (None, None, None)
except:
exc = sys.exc_info()
if exc != (None, None, None):
# Don't rely on sys.exc_info() still containing
# the right information. Another exception may
# have been raised and caught by an exit method
raise exc[0], exc[1], exc[2]