4

我正在尝试重新引发异常,以便为用户提供有关实际错误的更好信息。Python 3.3 包括PEP 409。它添加了raise NewException from None抑制原始异常上下文的语法。

但是,我的目标是 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

封装raise e_reraise from None在一个tryjust 中会产生一个更大的异常堆栈跟踪。版本检查也不起作用,因为我python3.3在 Xubuntu 12.10 上提取/usr/lib/python3/dist-packages/*了为 python3.2 模块设置的模块。(你会得到一个方便Error in sys.excepthook:,它会产生大量的回溯。)

有没有办法在 Python 3.3 中运行时使用 PEP 409 功能,而在 Python 3.2 中默默地忽略它?

4

2 回答 2

5

您可以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处理。

exc.__cause__ = None在 Python 3.2 中设置时,没有任何变化:

$ 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
于 2013-02-27T22:14:55.463 回答
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())

编辑:正如Martijn 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行相关的部分。这不是一项简单的任务,您最终会得到比其他解决方案更多的代码。

于 2013-02-27T22:17:10.347 回答