上下文管理器装饰方法中异常被静默忽略?代码未抛异常是Bug吗?
为什么上下文管理器内抛出的异常没有被传播?
这不是Bug,是你对上下文管理器的错误处理逻辑理解有误——问题出在finally块中的return语句上。
原因解析
Python中,如果finally块里存在return语句,它会覆盖并丢弃之前所有未处理的异常。你的代码里,__getitem__抛出的ValueError本来应该传播到上下文管理器外部,但finally中的return直接终止了上下文管理器的执行流程,异常被吞掉了,所以你看不到异常栈信息。
修正后的代码
只需要移除finally块里的return即可:
from contextlib import contextmanager class Dataset: _getToRaise = False def __getitem__(self, index): if self._getToRaise: print("It is supposed to raise here") raise ValueError return 0 @contextmanager def getToRaise(self): try: self._getToRaise = True print('Entering context manager') yield finally: print('Exiting context manager') self._getToRaise = False d = Dataset() with d.getToRaise(): d[0]
修正后的运行结果
执行上述代码后,你会看到预期的异常输出:
Entering context manager It is supposed to raise here Exiting context manager Traceback (most recent call last): File "test.py", line 22, in <module> d[0] File "test.py", line 8, in __getitem__ raise ValueError ValueError
补充说明
finally块的核心作用是保证清理逻辑(比如重置_getToRaise状态)无论是否发生异常都会执行,不需要通过return来结束它。Python会自动在finally块执行完成后,重新抛出之前捕获到的异常(如果存在)。
内容的提问来源于stack exchange,提问作者Vasilis Lemonidis
相关产品推荐
相关产品推荐

