python - Python sys.exc_info in finally 打印出无法捕获的异常
问题描述
我有以下代码:
import contextlib
import sys
class CC:
def __enter__(self):
pass
def __exit__(self, *args):
return True
@contextlib.contextmanager
def ctx():
try:
with CC():
yield
except:
print("has exception")
raise
finally:
print("finally")
print(sys.exc_info())
def test():
with ctx():
raise ValueError()
test()
这有点令人费解。但我的想法是我在 context 中提出了一个异常ctx
。因为退出时CC
返回True
,所以应该抑制异常。所以我希望该except
子句不会执行,并且子句中的sys.exc_info()
infinally
不会打印任何内容。
但实际情况是,except
子句并没有执行,而是sys.exc_info()
在finally
子句中打印出原来的异常。这让我感到困惑,因为不__exit__
返回 True 应该抑制异常?为什么那个except
和sys.exc_info()
看到的异常之间有差异?
解决方案
我找到了我的问题的答案。
因此,在上下文管理器中(使用@contextmanager
或显式定义__exit__
),当出现异常时,它会从yield
. 本质上,其余代码是在except
抛出代码中执行的。上下文管理器当然可以捕获并抑制重新引发的异常,但它不会改变它在except
子句中的事实,因此它仍在处理原始异常。这意味着即使重新引发的异常被捕获并抑制,sys.exc_info()
仍会显示原始异常。
举个例子,这意味着
@contextmanager
def ctx():
try:
try:
yield
except:
pass
except:
assert False
finally:
print(sys.exc_info())
with ctx():
raise ValueError()
ValueError
将在 中打印原件finally
,尽管外部except
不会捕获任何内容。
此外,我认为这意味着上下文管理器并不能完全替代代码重构。
with ctx:
try:
foo()
except:
...
不能总是转化为
@contextmanager
def fun():
with ctx:
try:
yield
except:
...
with fun():
do_something()
推荐阅读
- ios - 将数据从表格单元格发送到视图控制器时委托属性为空
- java - 连接 ignite 服务器节点时出现 NullPointerException
- javascript - 添加另一个带有线条的图层时无法单击标记
- android - Android 应用程序在获取数据时表现异常
- excel - 没有数据的值不会显示在数据透视表 excel 电源查询中
- c# - 如何使用 lambda 表达式来获取类型属性的属性?
- swagger-ui - 如何在 React Swagger UI 中预填充客户端 ID 和授权字段?
- shell - 用于显示给定数字范围内的完美数字的 Shell 脚本
- javascript - 具有条件渲染子级的动画组件
- python - Azure Blob 触发 Python 函数写入 CosmosDB 错误