Tur*_*ion 5 python iterator nested contextmanager
我有一个返回上下文管理器的迭代器。
我想要一个 pythonicwith
语句,它模拟多个嵌套语句的行为with
,每个嵌套语句对应迭代器返回的每个上下文管理器。
有人可能会说,我想要(已弃用的)函数的泛化contextlib.nested
。
contextlib.nested
有两个主要问题导致其被弃用。
__init__
or期间引发异常__new__
,并且这些异常将导致整个 with 语句中止而不调用__exit__
外部管理器。True
in捕获该异常__exit__
,则仍应执行该块。但在 的实现中nested
,它只是引发了 aRuntimeError
而不执行该块。这个问题可能需要完全重写nested
.但只需删除!定义中的一个就可以解决第一个问题。这改变了行为,不再接受参数列表(无论如何都没有用,因为已经可以处理它),而只接受迭代器。因此我将新版本称为“*
nested
nested
with
iter_nested
”。然后,用户可以定义一个迭代器,在迭代期间实例化上下文管理器。
带有生成器的示例:
def contexts():
yield MyContext1()
yield MyContext2()
with iter_nested(contexts()) as contexts:
do_stuff(contexts[0])
do_other_stuff(contexts[1])
Run Code Online (Sandbox Code Playgroud)
原来的代码和我修改后的版本的代码之间的区别nested
如下:
from contextlib import contextmanager
@contextmanager
--- def nested(*managers):
+++ def iter_nested(mgr_iterator):
--- #comments & deprecation warning
exits = []
vars = []
--- exc = (None, None, None)
+++ exc = None # Python 3
try:
--- for mgr in managers:
+++ for mgr in mgr_iterator:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
exits.append(exit)
yield vars
# All of the following is new and fit for Python 3
except Exception as exception:
exc = exception
exc_tuple = (type(exc), exc, exc.__traceback__)
else:
exc_tuple = (None, None, None)
finally:
while exits:
exit = exits.pop()
try:
if exit(*exc_tuple):
exc = None
exc_tuple = (None, None, None)
except Exception as exception:
exception.__context__ = exc
exc = exception
exc_tuple = (type(exc), exc, exc.__traceback__)
if exc:
raise exc
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3407 次 |
最近记录: |