============================== 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__`` 属性æ¥è·Ÿè¸ªå¼‚常链。例如: .. code-block:: python 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`` è¡ç”Ÿè€Œæ¥ã€‚ è¿™ç§å…³ç³»å¯ä»¥ä»Žå›žæº¯ç»“æžœä¸çœ‹å‡ºæ¥ã€‚ å¦‚æžœä½ åƒä¸‹é¢è¿™æ ·å†™ä»£ç ï¼Œä½ ä»ç„¶ä¼šå¾—到一个链接异常, ä¸è¿‡è¿™ä¸ªå¹¶æ²¡æœ‰å¾ˆæ¸…晰的说明这个异常链到底是内部异常还是æŸä¸ªæœªçŸ¥çš„编程错误。 .. code-block:: python try: ... except SomeException: raise DifferentException() å½“ä½ ä½¿ç”¨ ``raise from`` è¯å¥çš„è¯ï¼Œå°±å¾ˆæ¸…楚的表明抛出的是第二个异常。 最åŽä¸€ä¸ªä¾‹åä¸éšè—异常链信æ¯ã€‚ 尽管éšè—异常链信æ¯ä¸åˆ©äºŽå›žæº¯ï¼ŒåŒæ—¶å®ƒä¹Ÿä¸¢å¤±äº†å¾ˆå¤šæœ‰ç”¨çš„调试信æ¯ã€‚ ä¸è¿‡ä¸‡äº‹çš†å¹³ç‰ï¼Œæœ‰æ—¶å€™åªä¿ç•™é€‚当的信æ¯ä¹Ÿæ˜¯å¾ˆæœ‰ç”¨çš„。