捕获类中的异常

dav*_*000 14 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)
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*nts 18

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

就像是:

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()
Run Code Online (Sandbox Code Playgroud)

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

  • +1"你很可能不会想要这样的东西". (4认同)
  • 你能解释一下"你真的不想要这样的东西"吗?我有很多包含许多类的脚本,每个类都有很多方法.我想知道哪个类/方法失败了,没有写一个try/except (4认同)
  • +1对于演示*单独有用*,但我想再次强调OP,这真是一个坏主意... (3认同)

che*_*ner 14

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

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
Run Code Online (Sandbox Code Playgroud)

元类适用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"
Run Code Online (Sandbox Code Playgroud)

catch_exception装饰将寻找一个msg在它的参数属性,并使用它,如果发现,在处理异常.

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

def calc_handler(exc):
    # ...

calc.callback = calc_handler
Run Code Online (Sandbox Code Playgroud)

  • +1 - "__metaclass__"的好例子 - 如果OP最终会在脚下拍摄自己,至少在我们之间,我们提供了一些例子,以确保它们能够立即将其击垮....*咳嗽* (4认同)