使用/作为上下文管理器打开文件列表

Rya*_*ing 17 python with-statement contextmanager

注意:我知道

with open('f1') as f1, open('f2') as f2:
    ...
Run Code Online (Sandbox Code Playgroud)

句法.这是一个不同的问题.


给定一个字符串列表file_names有一种方法可以使用with/ as打开每个文件名,使用一行.像这样的东西:

with [open(fn) for fn in file_names] as files:
    # use the list of files
Run Code Online (Sandbox Code Playgroud)

这当然不起作用,因为它试图在列表上使用上下文管理器.在运行时之前可能无法知道列表的长度,例如sys.argv[1:]

Hen*_*ter 16

如果你有到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
Run Code Online (Sandbox Code Playgroud)


Max*_*Max 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
Run Code Online (Sandbox Code Playgroud)

输出是:

[<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>]
Run Code Online (Sandbox Code Playgroud)

请注意,它们在with context中打开并在外部关闭.

这是使用Python 上下文管理器API.

编辑:似乎这已经存在但已弃用:请参阅contextlib此SO问题.像这样使用它:

import contextlib

with contextlib.nested(*[open(fn, 'w') for fn in arr]) as files:
    print files
print files
Run Code Online (Sandbox Code Playgroud)