Python:异常修饰符。如何保存

2024-06-02 05:08:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在写一个装饰程序来应用于一个函数。它应该捕获任何异常,然后基于原始异常消息引发自定义异常。(这是因为suds抛出一个一般的WebFault异常,我从它的消息中解析web服务抛出的异常并引发一个Python异常来镜像它。)

但是,当我在包装器中引发自定义异常时,我希望stacktrace指向引发原始WebFault异常的函数。到目前为止,我得到的结果引发了正确的异常(它动态地解析消息并实例化异常类)。我的问题:如何保留stacktrace以指向引发WebFault异常的原始函数?

from functools import wraps

def try_except(fn):
        def wrapped(*args, **kwargs):
            try:
                fn(*args, **kwargs)
            except Exception, e:
                parser = exceptions.ExceptionParser()
                raised_exception = parser.get_raised_exception_class_name(e)
                exception = getattr(exceptions, raised_exception)
                raise exception(parser.get_message(e))
        return wraps(fn)(wrapped)

Tags: 函数parser消息defexceptionargsfn指向
2条回答

在Python 2.x中,raise的一个鲜为人知的特性是它可以与不止一个参数一起使用:三个参数形式的raise接受异常类型、异常实例和回溯。您可以使用sys.exc_info()获得回溯,它返回(不是一致的)异常类型、异常实例和回溯。

(这将异常类型和异常实例视为两个独立参数的原因是异常类之前的项目。)

所以:

import sys

class MyError(Exception):
    pass

def try_except(fn):
    def wrapped(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except Exception, e:
            et, ei, tb = sys.exc_info()
            raise MyError, MyError(e), tb
    return wrapped

def bottom():
   1 / 0

@try_except
def middle():
   bottom()

def top():
   middle()

>>> top()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tmp.py", line 24, in top
    middle()
  File "tmp.py", line 10, in wrapped
    return fn(*args, **kwargs)
  File "tmp.py", line 21, in middle
    bottom()
  File "tmp.py", line 17, in bottom
    1 / 0
__main__.MyError: integer division or modulo by zero

在Python 3中,这有点变化。在这里,回溯被附加到异常实例,并且它们有一个with_traceback方法:

raise MyError(e).with_traceback(tb)

另一方面,Python 3也有异常链接,这在许多情况下更有意义;要使用它,您只需使用:

raise MyError(e) from e

我已经面临这个问题,测试是由我的自定义装饰。

我在decorator主体中使用了以下构造来保留unittests输出中打印的原始跟踪:

try:
    result = func(self, *args, **kwargs)
except Exception:
    exc_type, exc_instance, exc_traceback = sys.exc_info()
    formatted_traceback = ''.join(traceback.format_tb(
        exc_traceback))
    message = '\n{0}\n{1}:\n{2}'.format(
        formatted_traceback,
        exc_type.__name__,
        exc_instance.message
    )
    raise exc_type(message)

相关问题 更多 >