捕获类中的异常

时间:2012-07-10 19:26:41

标签: python exception-handling

是否可以编写异常处理程序来捕获类中所有方法生成的运行时错误?我可以通过try / except包围每个人来完成它:

class MyError(Exception):
    def __init__(self, obj, method):
        print 'Debug info:', repr(obj.data), method.__name__
        raise

class MyClass:
    def __init__(self, data):
        self.data = data

    def f1(self):
        try:
            all method code here, maybe failing at run time
        except:
            raise MyError(self, self.f1)

我想知道是否有更通用的方法来实现相同的目标 - 因为在课堂的任何地方都会出现任何错误。我希望能够访问类数据以打印一些调试信息。 另外,如何获取失败的方法名称(示例中为f1)?

更新:感谢所有人提供的明确答案,装饰者的想法看起来就像是要走的路。 关于捕获所有异常的风险:raise分支中的except语句应该重新引发异常而不会丢失任何信息,不是吗?这就是我把它放在MyError中的原因......

3 个答案:

答案 0 :(得分:17)

警告:如果你想要这样的东西,很可能你不会......但如果你真的想...

类似的东西:

import functools

def catch_exception(f):
    @functools.wraps(f)
    def func(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception as e:
            print 'Caught an exception in', f.__name__
    return func

class Test(object):
    def __init__(self, val):
        self.val = val

    @catch_exception
    def calc():
        return self.val / 0

t = Test(3)
t.calc()

显示了如何装饰各个功能。然后,您可以创建一个类装饰器,将此装饰器应用于每个方法(注意classmethod's / staticmethod's / properties等...)

答案 1 :(得分:13)

假设你有@Jon Clement答案的装饰catch_exception ......

class ErrorCatcher(type):
    def __new__(cls, name, bases, dct):
        for m in dct:
            if hasattr(dct[m], '__call__'):
                dct[m] = catch_exception(dct[m])
        return type.__new__(cls, name, bases, dct)

class Test(object):
    __metaclass__ = ErrorCatcher

    def __init__(self, val):
        self.val = val

    def calc(self):
        return self.val / 0

元类将catch_exception应用于定义Test时看似方法的所有内容。


在回复有关每种方法的自定义消息的评论时,可以附加这样的消息(甚至是回调函数来生成消息)作为属性:

class Test(object):
    __metaclass__ = ErrorCatcher
    def __init__(self, val):
        self.val = val

    def calc(self):
        return self.val / 0

    calc.msg = "Dividing by 0 is ill-advised"

catch_exception装饰器会在其参数上查找msg属性,并在处理异常时使用它(如果找到)。

这种方法可以延长;而不是字符串,msg可以是异常类型到字符串的映射。在任何一种情况下,都可以使用任意回调函数替换字符串(当然,支持来自catch_exception),例如,将引发的异常作为参数。

def calc_handler(exc):
    # ...

calc.callback = calc_handler

答案 2 :(得分:3)

装饰者在这里是一个很好的解决方案。

以下是您如何做到这一点的示例:

import inspect

def catch_exception_decorator(function):
   def decorated_function:
      try:
         function()
      except:
         raise MyError(self.__class__, inspect.stack()[1][3])
   return decorated_function

class MyClass(object):
    def __init__(self):
         ...

    @catch_exception_decorator
    def f1(self):
         ...

@catch_exception_decorator在函数顶部是f1 = catch_exception_decorator(f1)的快捷方式。

除了自我。之外,您还可以从实例访问类数据,只要您没有隐藏变量。 inspect.stack()[1] [3]是当前函数的函数名。您可以使用它们来创建例外属性。