让我详细说明这个隐秘的问题标题。
在Python 3中,我们提供了巧妙的异常链接功能,该功能可让您在异常传播过程中为异常添加更多上下文。
最近,我想在异常上附加额外的异常信息,但又不要直接抛出。该代码在生成器中进行了一些防御性处理,因此我想让其产生,因此我尝试了类似的操作:
def gen():
for row in csv_file:
try:
yield parse(row)
except Exception as e:
yield RuntimeError(f"Bad row: {row}") from e
令我失望的是,这没有用!原来raise EXCEPTION from CAUSE
是复合运算符,如PEP-3134所述。
要在我的代码中解决此问题,我手动设置了__cause__ = e
并继续进行。但是,它仍然困扰着我为什么以这种方式实施。
想象,取而代之的是,我们有一个运算符from
,其语法如下:EXCEPTION from CAUSE
,除了抛出并返回新的{ {1}}。这样:
raise .. from ..
语法(现在在内部将其解析为Exception
)raise .. from ..
运算符)。从Python语言开发人员的角度来看,我将其视为运算符“替代形式”的主要论点。我已经通过PEP / google进行过搜索,但是并没有真正找到任何理由。我尝试检查是否设置了raise (.. from ..)
以外的其他内容,但事实并非如此。我附加了一些我用来检查的代码:
raise
它产生相同的回溯:
__cause__
def failing():
raise RuntimeError("function failed!")
def cause_from():
try:
failing()
except Exception as e:
raise RuntimeError("extra info") from e
def cause_manual():
try:
failing()
except Exception as e:
ee = RuntimeError("extra info")
ee.__cause__ = e
raise ee
回溯中的唯一区别是引发异常的行($ python3 -c 'import exc; exc.cause_from()'
Traceback (most recent call last):
File "/tmp/exc.py", line 7, in cause_from
failing()
File "/tmp/exc.py", line 2, in failing
raise RuntimeError("function failed!")
RuntimeError: function failed!
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/tmp/exc.py", line 9, in cause_from
raise RuntimeError("extra info") from e
RuntimeError: extra info
与$ python3 -c 'import exc; exc.cause_manual()'
Traceback (most recent call last):
File "/tmp/exc.py", line 13, in cause_manual
failing()
File "/tmp/exc.py", line 2, in failing
raise RuntimeError("function failed!")
RuntimeError: function failed!
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/tmp/exc.py", line 17, in cause_manual
raise ee
RuntimeError: extra info
)。 raise RuntimeError("extra info") from e
版本看起来更具可读性。
所以这是我看到选择语法结构的唯一原因,我想知道这是否也是预期的动机?我有可能会错过raise ee
作为复合运算符的微妙效果吗?