在Python中展平`with`和`try / finally`

时间:2017-05-30 09:29:39

标签: python python-3.x

请考虑以下代码:

async with app:
    ...
    async with app.resource as rsrc:
        ...
        async with rsrc.foo as bar:
            ...

拥有大量嵌套的withasync with语句会对代码的可读性产生负面影响,尤其是在测试中,同一条款可能会多次重复使用。

在像D这样的语言中,有scope(exit) ...构造,它允许您将代码附加到范围终结器列表中 - 这个代码将在范围保留后执行,允许您有效地执行{{1但是没有添加缩进。

有没有办法在Python中压扁__exit__并执行类似的操作?

with

或者,有没有办法在退出范围时可靠地执行任意代码?

2 个答案:

答案 0 :(得分:0)

据我所知,你无法达到你想要的效果。特别是因为没有可能定义这样的“范围”。

即使在您的伪代码中:

await async_with(app)
scope_exit(app.quit)

...

rsrc = await async_with(app.resource)
scope_exit(rsrc.release)

...

bar = await async_with(rsrc.foo)
scope_exit(lambda: bar.unfrob())

raise ExceptionHere()

应该[不]抓住它的背景?

我可能错了,但设置“保护”以捕获异常的唯一方法是try/except子句。 with大致是它的包装。

谈到动机,如果你对嵌套上下文管理器的问题如此困难,你应该重构你的核心以提取内部上下文作为函数。您可以查看contextlib帮助者

答案 1 :(得分:0)

我无法忍受with声明中的额外缩进...这就是我要做的事情来压扁它们:

嵌套:

def stuff_with_files(path_a, path_b):
    # ... do stuff
    with open(path_a) as fileA:
        # ... do stuff with fileA
        with open(path_b) as fileB:
            # ... do stuff with fileA and fileB

def main():
    stuff_with_files('fileA.txt', 'fileB.txt')

扁平:

# Extract the 'with' statement.
def with_file(path, func, *args, **kwargs):
    with open(path) as file:
        func(file, *args, **kwargs)


def process_a_b(fileB, results_of_a):
    # ... do stuff with fileB and results_of_a.


def process_a(fileA):
    # ... do stuff with fileA
    results = # ...
    with_file('fileB.txt', process_a_b, results)


def main():
    with_file('fileA.txt', process_a)