Python 2.7 中的多个 with 语句使用列表理解

Multiple with statements in Python 2.7 using a list comprehension

问题:

我有兴趣在 inside 一个 Python with 语句中做一个列表理解,这样我就可以同时打开多个上下文管理器最小的语法。我正在寻找适用于 Python 2.7.

的答案

考虑以下代码示例。我想同时对任意长列表 中的变量使用 with 语句 ,最好以语法清晰的方式使用。

def do_something(*args):
    contexts = {}
    with [open(arg) as contexts[str(i)] for i, arg in enumerate(args)]:
        do_another_thing(contexts)

do_something("file1.txt", "file2.txt")

有人知道是否有办法在 Python 2.7 中的 with 语句中涉及列表理解吗?


类似问题的回答:

以下是我已经看过的一些内容,并解释了为什么它们不适合我的目的:

对于 Python 2.6-,我可以使用 contextlib.nested 来完成这个有点像:

def do_something(*args):
    contexts = {}
    with nested(*[open(arg) for arg in args]) as [contexts[str(i)] for i in range(len(args))]:
        do_another_thing(contexts)

然而,这在 Python 2.7+ 中已被弃用,所以我认为使用它是不好的做法。

相反,新语法是在 this SO answer, as well as this SO answer 上给出的:

with A() as a, B() as b, C() as c:
    doSomething(a,b,c)

但是,我需要能够处理任意输入列表,就像我上面给出的示例一样。这就是为什么我赞成列表理解。

对于 Python 3.3+this SO answer 描述了如何使用 ExitStack 来完成。但是,我在 Python 2.7.

中工作

还有this solution,但我不想自己写class来完成这个。

是否有希望在 Python 2.7 中结合列表理解和 with 语句?

更新 1-3:更新示例以更好地强调我正在寻找的功能

更新 4:发现另一个 similar question。这个有一个答案也建议 ExitStack,一个在 2.7 中不可用的函数。

with 语句的主要任务是调用其上下文管理器的 __exit__ 属性。专门用于处理文件。因此,在这种情况下,由于这一点以及 open() returns 和 file_object 的事实,您可以使用列表理解来创建文件对象列表并调用 exit()/close() 手动。但请注意,在这种情况下,您必须手动处理异常。

def print_files(*args):
    f_objs = [open(arg) for arg in args]
    # do what you want with f_objs
    # ...
    # at the end
    for obj in f_objs:
        f.close()

请注意,如果您只想 运行 对文件对象进行一些并行操作,我推荐这种方法,否则最好的方法是在 for 循环中使用 with 语句,并且在每次迭代中打开文件(按名称),如下所示:

for arg in args:
    with open(arg) as f:
         # Do something with f

为了更安全,您也可以使用自定义 open 函数来处理异常:

def my_open(*args, **kwargs):
    try:
        file_obj = open(*args, **kwargs)
    except Exception as exp:
        # do something with exp and return a proper object
    else:
        return file_obj

def print_files(*args):
    f_objs = [my_open(arg) for arg in args]
    # do what you want with f_objs
    # ...
    # at the end
    for obj in f_objs:
        try:
            f.close()
        except Exception as exp:
            # handle the exception

自己做这件事真的很棘手,尤其是处理打开或关闭文件时发生的异常。我建议只获得一个像 contextlib2 这样实现 contextlib.ExitStack 功能的库。那么你可以做

with contextlib2.ExitStack() as stack:
    files = [stack.enter_context(open(arg)) for arg in args]
    ...

就像您使用 Python 3 中的 contextlib.ExitStack 一样,一切都会为您正确处理。