4

我想重新提出一個異常,讓用戶更好地瞭解有關實際錯誤的信息。 Python 3.3包括PEP 409。它添加了raise NewException from None語法來抑制原始異常的上下文。我如何在Python 3.2程序中優雅地將Python 3.3從無例外語法中包含進來?

但是,我的目標是Python 3.2。 Python腳本將解析,但在運行時如果遇到from None語法,它將產生TypeError: exception causes must derive from BaseException。例如:

try: 
    regex_c = re.compile('^{}$'.format(regex)) 
except re.error as e: 
    e_msg = 'Regular expression error in "{}"'.format(regex) 
    e_reraise = Exception(e_msg) 
    # Makes use of the new Python 3.3 exception syntax [from None] 
    # to suppress the context of the original exception 
    # Causes an additional TypeError exception in Python 3.2 
    raise e_reraise from None 

封裝在一個tryraise e_reraise from None只是產生甚至更大的異常堆棧跟蹤。版本檢查也不起作用,因爲我在Xubuntu 12.10上的python3.3/usr/lib/python3/dist-packages/*中獲取模塊,這是爲python3.2模塊設置的。 (你得到一個方便Error in sys.excepthook:它創建了一個龐大的回溯

有沒有在Python 3.3運行時,而在Python 3.2靜靜地忽略它使用PEP 409功能的方法嗎?

+0

版本檢查有什麼問題? – wRAR 2013-02-27 21:55:53

+0

@wRAR版本檢查似乎不適用於像我的系統,它有python3.3解釋器,但使用一個通用的python3 stdlib來設置不同的版本(在我的情況下是python3.2)。 – 2013-02-27 21:57:58

+0

@SumantManne:你覺得'import sys; print(sys.version_info)'在那種情況下給你? – 2013-02-27 22:00:40

回答

3

您鏈接的PEP提供瞭解決方案:

  • raise NewException() from None

如下明確聲明始發 例外

  • exc = NewException(); exc.__context__ = None; raise exc

以前的方法的非常詳細的方式存在語法

所以,你只需要避免新的語法,並使用冗長的等價物。

如果你不希望看到的作業,你可以把代碼放到一個函數:

def suppress_context(exc): 
    exc.__context__ = None 
    return exc 

然後執行:

raise suppress_context(TheErrorClass()) 

編輯:由馬亭指出, PEP 415更改了此行爲:

總之,raise exc from cause將等同於:

exc.__cause__ = cause 
raise exc 

因此,而不是設置__context__None你應該設置__cause__None

如果您確實想要使用新的語法,那麼唯一的方法就是將sys.excepthook替換爲解析回溯輸出並移除不需要的部分。但在這種情況下,你還必須此:

try: 
    raise error from None 
except TypeError: 
    raise error 

然後excepthook應搜索回溯,如果它應該刪除相關raise error from None線部分。不是一個簡單的任務,並且最終得到的代碼比另一個解決方案更多。

+0

不是'__context__',而是**'__cause__' **應該設置爲'None'。我也試過'__context__',沒有什麼改變(也沒有設置__suppress_context__工作)。 PEP 409被PEP 415修改。 – 2013-02-27 22:45:16

+0

@MartijnPieters正確,我現在正在修復此問題。 – Bakuriu 2013-02-27 22:57:18

+0

卑微的建議:爲什麼我們不把*當前正確的*代碼放在帖子的頂部,以便在歷史正確答案之前先閱讀現代答案? – 2017-01-01 17:46:33

4

您可以設置exc.__cause__ = None壓制在Python 3.3的情況下打印:

except re.error as e: 
    e_msg = 'Regular expression error in "{}"'.format(regex) 
    e_reraise = Exception(e_msg) 
    e_reraise.__cause__ = None # 'raise e_reraise from None' 
    raise e_reraise  

在Python 3.3,當您使用raise exc from cause真正發生的是:

exc.__cause__ = cause 
raise exc 

,進而暗中設置exc.__cause__exc.__suppress_context__ = True。請參閱PEP 415,其中詳細說明了如何處理raise exc from None

當你在Python 3.2設置exc.__cause__ = None,沒有什麼變化:

$ python3.2 
Python 3.2.3 (default, Apr 13 2012, 13:31:19) 
[GCC 4.2.1 Compatible Apple Clang 3.0 (tags/Apple/clang-211.12)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> try: 
...  raise ValueError() 
... except: 
...  exc = TypeError() 
...  exc.__cause__ = None 
...  raise exc 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
ValueError 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "<stdin>", line 6, in <module> 
TypeError 

但是在Python 3.3,上下文被抑制,而不是:

$ python3.3 
Python 3.3.0 (default, Sep 29 2012, 08:16:08) 
[GCC 4.2.1 Compatible Apple Clang 3.1 (tags/Apple/clang-318.0.58)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> try: 
...  raise ValueError() 
... except: 
...  exc = TypeError() 
...  exc.__cause__ = None 
...  raise exc 
... 
Traceback (most recent call last): 
    File "<stdin>", line 6, in <module> 
TypeError 

就像您曾使用raise exc from None

>>> try: 
...  raise ValueError() 
... except: 
...  raise TypeError() from None 
... 
Traceback (most recent call last): 
    File "<stdin>", line 4, in <module> 
TypeError