请考虑以下代码:
async with app:
...
async with app.resource as rsrc:
...
async with rsrc.foo as bar:
...
拥有大量嵌套的with
或async with
语句会对代码的可读性产生负面影响,尤其是在测试中,同一条款可能会多次重复使用。
在像D这样的语言中,有scope(exit) ...
构造,它允许您将代码附加到范围终结器列表中 - 这个代码将在范围保留后执行,允许您有效地执行{{1但是没有添加缩进。
有没有办法在Python中压扁__exit__
并执行类似的操作?
with
或者,有没有办法在退出范围时可靠地执行任意代码?
答案 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)