簡體   English   中英

Python sys.exc_info in finally 打印無法捕獲的異常

[英]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 不應該抑制異常嗎? 為什么exceptsys.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM