注意:我知道
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
当然,它尝试在列表中使用上下文管理器时不起作用。在运行时之前可能无法知道列表的长度,例如sys.argv[1:]
答案 0 :(得分:15)
如果您可以访问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
答案 1 :(得分:7)
这个怎么样?
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>]
注意,它们在with context中打开并在外面关闭。
这是使用Python context manager API。
编辑:看起来这已经存在但已弃用:请参阅contextlib和this SO question。像这样使用它:
import contextlib
with contextlib.nested(*[open(fn, 'w') for fn in arr]) as files:
print files
print files
答案 2 :(得分:1)
听起来你基本上都在寻找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]