繁体   English   中英

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

[英]Python decorated exception cant be excepted

我使用了一个装饰器类来装饰一个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'

首先,方法__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'

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

你需要意识到Err是什么。 Decorator的工作方式与普通定义类似,但在分配名称之前将装饰器应用于对象。 这相当于:

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

现在Err是一个ClsDecor实例,在提升它时你正在调用实例(而不是类),你将调用ClsDecor.__call__ (而不是ClsDecor.__init__ )。 当你尝试用参数( args )调用self.cls时就会发生Err ,但是self.clsErr ,它不带任何额外的参数(除了self )。

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

except Exception as e:
    print 'Not catched', repr(e)
    raise

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

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

    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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM