使用列表推导

时间:2016-08-08 17:02:46

标签: python python-2.7 list-comprehension with-statement

问题:

我有兴趣在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以及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,但我宁愿不写自己的课来完成这项工作。

是否有希望在Python 2.7中结合使用列表推导和with语句?

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

更新4:找到另一个similar question 。这个答案也提出了ExitStack,这个函数在2.7中没有。

2 个答案:

答案 0 :(得分:2)

with语句的主要任务是调用其上下文管理器的__exit__属性。特别用于处理文件。因此,在这种情况下,由于这一点以及open()返回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

答案 1 :(得分:2)

自己这样做非常棘手,特别是处理打开或关闭文件时发生的异常。我建议您只使用contextlib2这样的库来实现contextlib.ExitStack功能。然后就可以了

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

就像你在Python 3中使用contextlib.ExitStack一样,一切都正确处理。