如何解决python contextmanager 如何将异常重新引发回装饰生成器?
这是一个关于 contextmanager
如何做它所做的事情的问题。
contextmanger
是一个装饰器,它调用被装饰的函数(一个生成器)两次,以构建 __enter__
和 __exit__
函数,由 with
条款,到目前为止一切顺利。我不明白的是——当在 with
块内引发异常时,生成器内的 except
块 怎么能捕获它吗?
@contextmanager
def f():
try:
yield 'foo'
except Exception as e:
print('How can I ever reach here??')
print(e)
finally:
print('finally')
with f() as p:
print(p)
raise Exception('bar')
输出是
foo
How can I ever reach here??
bar
finally
我认为魔法发生在 @contextmanager
中,因为如果我移除装饰器,并且只在 try 块内执行“yield”,则生成器内部不会捕获生成器外部的异常:
def f():
try:
yield 'foo'
except Exception as e:
print('How can I ever reach here??')
print(e)
finally:
print('finally')
g = f()
print(next(g))
raise Exception('bar')
输出是
foo
Traceback (most recent call last):
...
Exception: bar
我查看了 contextlib.contextmanager
代码,但仍然无法弄清楚使用纯 python 代码如何做到这一点。关于我在这里错过的语言的一些基本知识?
解决方法
让您感到困惑的逻辑是 _GeneratorContextManager
。您的函数 f
是 self.gen。代码刚刚调用了 next(self.gen)
,取回了字符串 "foo"
,并且正在等待。 f()
位于 yield
语句的中间。
此时您抛出异常。由于 python 看到您在 with
块中,(这些都内置在语言中),它调用生成器的 __exit__
方法,并使用描述错误的参数。这就是上下文管理器的工作方式。上下文管理器调用 self.gen.throw
,它通过抛出异常来恢复生成器。进去。瞧。您在异常处理程序中。
这样会更清楚吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。