中的Python sys.exc_info最终打印一个异常,该异常可以';不要被抓住

中的Python sys.exc_info最终打印一个异常,该异常可以';不要被抓住,python,Python,我有以下代码: 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: pri

我有以下代码:

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()
打印原始异常。这让我很困惑,因为
\uuuuuu exit\uuuuu
返回True不应该抑制异常吗?为什么
except
sys.exc_info()
之间存在差异?我找到了问题的答案

因此,在上下文管理器中(使用
@contextmanager
或显式定义的
\uuuu退出\uuuuuu
),当出现异常时,它会从
产出中抛出。本质上,除了抛出代码的
,其余代码都在
中执行。当然,上下文管理器可以捕获并抑制重新引发的异常,但它不会改变它位于
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
,但外部
除外
不会捕获任何内容

此外,我认为这意味着上下文管理器并不是代码重构的完全替代品

with ctx:
    try:
        foo()
    except:
        ...
不能总是转化为

@contextmanager
def fun():
    with ctx:
        try:
            yield
        except:
            ...

with fun():
    do_something()