[英]Python sys.exc_info in finally prints an exception that can't be caught
我有以下代碼:
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()
這有點令人費解。 但是我的想法是我在上下文ctx
中提出了一個異常。 因為CC
在退出時返回True
,所以應該抑制異常。 所以我希望except
子句不會執行,並且finally
子句中的sys.exc_info()
不會打印任何內容。
但實際情況是, except
子句沒有執行,但finally
子句中的sys.exc_info()
打印出原始異常。 這讓我很困惑,因為__exit__
返回 True 不應該抑制異常嗎? 為什么except
和sys.exc_info()
看到的異常之間存在差異?
我找到了我的問題的答案。
因此,在上下文管理器中(使用@contextmanager
或明確定義的__exit__
),當出現異常時,它會被拋出yield
。 本質上,代碼的 rest 正在執行, 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()
將在finally
中打印原始的ValueError
,盡管外部except
不會捕獲任何內容。
此外,我認為這意味着上下文管理器並不能完全替代代碼重構。
with ctx:
try:
foo()
except:
...
不能總是轉化為
@contextmanager
def fun():
with ctx:
try:
yield
except:
...
with fun():
do_something()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.