Python装饰的异常不能被排除在外

时间:2017-04-10 04:46:41

标签: python exception decorator

我使用了一个装饰器类来装饰一个Exception,但是,似乎异常似乎无法使用确切的异常类进行例外处理。使用functools.update_wrapper更新装饰器类也不起作用。

class ClsDecor(object):

    def __init__(self,cls):
        self.cls=cls
        self.counter=0

    def __call__(self,*args):
        self.counter+=1
        return self.cls(*args)

@ClsDecor
class Err(Exception):
    def __init__(self):
      Exception.__init__(self)

try:
    raise Err()
except Err as e:
    print 'catched'
except Exception as e:
    print 'Not catched'

3 个答案:

答案 0 :(得分:2)

首先,方法__call__应为:

def __call__(self, *args):
    return self.cls(*args)

您的代码会在__call__内引发错误并直接转到print 'Not catched',这是第一级错误。修复此错误后,您将达到类型不匹配的第二级错误,这在dhke的评论中得到了很好的解释。基本的想法是,Err实际上是ClsDecor之后的@ClsDecor类型,但您在Err中返回了原始类型__call__的实例,这显然不匹配except Err。您可以轻松地使用装饰器来存档您的目的,如:

def err_dec(Cls):
    class NewErr(Exception):
        def __init__(self, *args, **kwargs):
            self.err = Cls(*args, **kwargs)
return NewErr

@err_dec
class Err(Exception):
    def __init__(self):
        Exception.__init__(self)

更新了评论中的要求:

def err_dec(Cls):
    class NewErr(Exception):
        c = 0
        def __init__(self, *args, **kwargs):
            NewErr.c = NewErr.c + 1
            self.err = Cls(*args, **kwargs)
        def counter(self):
            return NewErr.c
    return NewErr

@err_dec
class Err(Exception):
    def __init__(self):
        Exception.__init__(self)

try:
    Err()
    Err()
    raise Err()
except Err as e:
    print e.counter()
    print 'catched'
except Exception as e:
    print 'Not catched'

答案 1 :(得分:0)

问题不在于装饰。也许装饰让你困惑,但这不是问题。

您需要了解Err是什么。 Decorator的工作方式与普通定义类似,但在分配名称之前将装饰器应用于对象。这就等同于:

class Err(Exception):
def __init__(self):
  Exception.__init__(self)
Err = ClsDecor(Err)

现在Err是一个ClsDecor实例,在提升它时你将调用实例(而不是类),你将调用ClsDecor.__call__(而不是{ {1}})。当你尝试使用参数(ClsDecor.__init__)调用self.cls时会发生错误,但argsself.cls,它不会接受任何其他参数(除了Err)。

如果您在默认的self子句中打印了错误,您会看到这一点。如果你点击默认条款,打印错误是一个好主意,因为它常常是因为你遇到了意外的异常:

except

或许你根本不应该抓住它 - 如果没有发现异常,那么无论如何都会打印回溯。

答案 2 :(得分:0)

在所有人的帮助下,我终于得到了这样的解决方案:

    class ErrMetaClass(type):
        def __new__(mcls,cls_name,cls_parents,cls_attr):
            return super(ErrMetaClass,mcls).__new__(mcls, 
                   cls_attr['_cls'].__name__, cls_parents,cls_attr)

    def err_dec(cls):
        class NewErr(Exception):
            __metaclass__ = ErrMetaClass
            _cls=cls
            c=0
            def __init__(self):
                NewErr.c+=1
        return NewErr

    @err_dec
    class Err(Exception):
        def __init__(self):
          Exception.__init__(self)

    try:
        raise Err()
    except Err as e:
        print Err.c
    except Exception as e:
        print type(e)