14.9 �获异常�抛出�外的异常¶
问题¶
ä½ æƒ³æ�•获一个异常å�ŽæŠ›å‡ºå�¦å¤–一个ä¸�å�Œçš„异常,å�Œæ—¶è¿˜å¾—在异常回溯ä¸ä¿�留两个异常的信æ�¯ã€‚
解决方案¶
为了链接异常,使用 raise from è¯å�¥æ�¥ä»£æ›¿ç®€å�•çš„ raise è¯å�¥ã€‚
å®ƒä¼šè®©ä½ å�Œæ—¶ä¿�留两个异常的信æ�¯ã€‚例如:
>>> def example():
... try:
... int('N/A')
... except ValueError as e:
... raise RuntimeError('A parsing error occurred') from e
...
>>> example()
Traceback (most recent call last):
File "<stdin>", line 3, in example
ValueError: invalid literal for int() with base 10: 'N/A'
上é�¢çš„异常是下é�¢çš„å¼‚å¸¸äº§ç”Ÿçš„ç›´æŽ¥åŽŸå› ï¼š
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in example
RuntimeError: A parsing error occurred
>>>
在回溯ä¸å�¯ä»¥çœ‹åˆ°ï¼Œä¸¤ä¸ªå¼‚常都被æ�•获。
è¦�想æ�•èŽ·è¿™æ ·çš„å¼‚å¸¸ï¼Œä½ å�¯ä»¥ä½¿ç”¨ä¸€ä¸ªç®€å�•çš„ except è¯å�¥ã€‚
ä¸�è¿‡ï¼Œä½ è¿˜å�¯ä»¥é€šè¿‡æŸ¥çœ‹å¼‚常对象的 __cause__ 属性æ�¥è·Ÿè¸ªå¼‚常链。例如:
try:
example()
except RuntimeError as e:
print("It didn't work:", e)
if e.__cause__:
print('Cause:', e.__cause__)
当在 except å�—ä¸å�ˆæœ‰å�¦å¤–的异常被抛出时会导致一个éš�è—�的异常链的出现。例如:
>>> def example2():
... try:
... int('N/A')
... except ValueError as e:
... print("Couldn't parse:", err)
...
>>>
>>> example2()
Traceback (most recent call last):
File "<stdin>", line 3, in example2
ValueError: invalid literal for int() with base 10: 'N/A'
在处�上述异常的时候,�外一个异常�生了:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in example2
NameError: global name 'err' is not defined
>>>
这个例å�ä¸ï¼Œä½ å�Œæ—¶èŽ·å¾—äº†ä¸¤ä¸ªå¼‚å¸¸çš„ä¿¡æ�¯ï¼Œä½†æ˜¯å¯¹å¼‚常的解释ä¸�å�Œã€‚
这时候,NameError 异常被作为程åº�最终异常被抛出,而ä¸�是ä½�于解æž�异常的直接回应ä¸ã€‚
å¦‚æžœï¼Œä½ æƒ³å¿½ç•¥æŽ‰å¼‚å¸¸é“¾ï¼Œå�¯ä½¿ç”¨ raise from None :
>>> def example3():
... try:
... int('N/A')
... except ValueError:
... raise RuntimeError('A parsing error occurred') from None
...
>>>
example3()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in example3
RuntimeError: A parsing error occurred
>>>
讨论¶
在设计代ç �时,在å�¦å¤–一个 except 代ç �å�—ä¸ä½¿ç”¨ raise è¯å�¥çš„æ—¶å€™ä½ è¦�特别å°�心了。
大多数情况下,这ç§� raise è¯å�¥éƒ½åº”该被改æˆ� raise from è¯å�¥ã€‚ä¹Ÿå°±æ˜¯è¯´ä½ åº”è¯¥ä½¿ç”¨ä¸‹é�¢è¿™ç§�å½¢å¼�:
try:
...
except SomeException as e:
raise DifferentException() from e
è¿™æ ·å�šçš„åŽŸå› æ˜¯ä½ åº”è¯¥æ˜¾ç¤ºçš„å°†åŽŸå› é“¾æŽ¥èµ·æ�¥ã€‚
也就是说,DifferentException 是直接从 SomeException �生而�。
è¿™ç§�关系å�¯ä»¥ä»Žå›žæº¯ç»“æžœä¸çœ‹å‡ºæ�¥ã€‚
å¦‚æžœä½ åƒ�下é�¢è¿™æ ·å†™ä»£ç �ï¼Œä½ ä»�然会得到一个链接异常, ä¸�过这个并没有很清晰的说明这个异常链到底是内部异常还是æŸ�个未知的编程错误。
try:
...
except SomeException:
raise DifferentException()
å½“ä½ ä½¿ç”¨ raise from è¯å�¥çš„è¯�,就很清楚的表明抛出的是第二个异常。
最å�Žä¸€ä¸ªä¾‹å�ä¸éš�è—�异常链信æ�¯ã€‚ 尽管éš�è—�异常链信æ�¯ä¸�利于回溯,å�Œæ—¶å®ƒä¹Ÿä¸¢å¤±äº†å¾ˆå¤šæœ‰ç”¨çš„调试信æ�¯ã€‚ ä¸�过万事皆平ç‰ï¼Œæœ‰æ—¶å€™å�ªä¿�留适当的信æ�¯ä¹Ÿæ˜¯å¾ˆæœ‰ç”¨çš„。