八叶一刀·无仞剑

万物流转,无中生有,有归于无

导航

Python类装饰器

Posted on 2019-11-16 17:04  闪之剑圣  阅读(13424)  评论(0编辑  收藏  举报

上次介绍了Python的函数装饰器,这次我们来讲一讲Python的类装饰器。

Python的类装饰器基本语法如下:

def decorator(cls):
    print "6666666"
    return cls
    
@decorator
class Model(object):
    def __init__(self):
        print "model created"

if __name__ == '__main__':
    model = Model()

decorator即是装饰器函数,输入的cls是一个类,返回也是一个类(其实返回一个可调用对象就可以,例如函数)。所以其实上文的类装饰器就相当于:

Model = decorator(Model)

由于装饰器是在加载该模块时运行的,因此上文代码中装饰器输出的"6666666"只会在加载该模块时输出一次。

这只是最基本的版本,既然返回只要是一个可调用对象就可以,我们就可以对输入的类进行一系列魔改:

class A(object):
    def __init__(self):
        print "77777"

def decorator(cls):
    return A

@decorator
class Model(object):
    def __init__(self):
        print "model created"

if __name__ == '__main__':
    model = Model()
    print model

输出为:

77777
<__main__.A object at 0x00B0F850>

可以看到,通过类装饰器,已经把返回的类悄悄地进行了替换,最终生成的其实是A的对象。

类装饰器可以对类对象进行修改:

def decorator(cls):
    cls.test_val = 1
    return cls
    
@decorator
class Model(object):
    test_val = 0
    def __init__(self):
        pass

if __name__ == '__main__':
    model = Model()
    print model.test_val

经过类装饰器的修饰,Model类的test_val值已经被改成了1。

类装饰器也可以带参数:

def decorator(num):
    print num
    def dec2(cls):
        return cls
    return dec2
    
@decorator(1)
class Model(object):
def __init__(self): pass

最后要注意的是,对于继承关系,若f装饰了类A,类B继承了A,则产生B的对象时仍然会调用装饰器f,但装饰器f只会修饰类A。如下代码所示:

def decorator(num):
    print num
    def dec2(cls):
        print cls
        return cls
    return dec2

def decorator2(cls):
    print cls
    return cls
    
@decorator(1)
class Model(object):
    test_val = 0
    def __init__(self):
        pass

@decorator2
class SubModel(Model):
    def __init__(self):
        pass

if __name__ == '__main__':
    model = SubModel()

得到的输出为:

1
<class '__main__.Model'>
<class '__main__.SubModel'>

第一行和第二行是由decorator输出的,第三行是由decorator2输出的。对decorator来说,它只知道Model的存在,因此在decorator中调用SubModel的对象则会报错。