python Decorator装饰器用法二

类装饰器是用来装饰python类的,使用方法就是在类定义的头部加上@decorator

基本用法如下:

#-*- coding:utf-8 -*-
def decorator(original_cls):
    class Wrapper:
        def __init__(self, *args):
            print "Wrapper __init__",args
            self.original_inst = original_cls(*args)
        def __getattr__(self, name):
            print "Wrapper:__getattr__",name
            return getattr(self.original_inst, name)
    return Wrapper

@decorator
class A:
    def __init__(self, x, y):
        self.firstName = u'小二'
        self.lastName = u'王'
        print "A:__init__",x,y

x = A(6, 7)
print(x.lastName)
print(x.firstName)
代码返回结果如下:

Wrapper __init__ (6, 7)
A:__init__ 6 7
Wrapper:__getattr__ lastName

Wrapper:__getattr__ firstName
小二

decorator函数接受一个类做为入参,返回一个新类Wrapper。

A(6,7)其实是Wrapper(6,7),所以首先实例化Wrapper,调用Wrapper的__init__函数,在Wrapper的__init__函数中,生成了原A类的一个实例,所以紧接着调用了A的__init__函数。

x.lastName语句,x其实是Wrapper的实例,该实例没有lastName属性,调用类任何没有的实例都会调佣该类的 __getattr__,所以首先调用了Wrapper的__getattr__函数,__getattr__函数调用了getattr(self.original_inst,name),其实就是调用了Wrapper实例中保存的A类实例的lastName属性,所以正确的返回了属性值“王”。

不用装饰器语法等价代码如下:

#-*- coding:utf-8 -*-
def decorator(original_cls):
    class Wrapper:
        def __init__(self, *args):
            print "Wrapper __init__",args
            self.original_inst = original_cls(*args)

        def __getattr__(self, name):
            print "Wrapper:__getattr__",name
            return getattr(self.original_inst, name)
    return Wrapper
class A:
    def __init__(self, x, y):
        self.firstName = u'小二'
        self.lastName = u'王'
        print "A:__init__",x,y
A = decorator(A)  #这里是关键代码

x = A(6, 7)
print(x.lastName)
print(x.firstName)

类装饰器一个常见的错误用法把装饰器decorator定义为一个类,把被装饰的类存放在该类的成员变量中,当获取原类的属性时,使用__getattr__函数进行截获,然后在该函数中使用getattr获取原类的属性。代码如下:

#-*- coding:utf-8 -*-
class Decorator:
    def __init__(self, C):
        self.orignalClass = C
        print"__init__"
    def __call__(self, *args):
        self.wrapped = self.orignalClass(*args)
        print "__call__",self.wrapped.name
        return self
    def __getattr__(self, attrname):
        return getattr(self.wrapped, attrname)

@Decorator
class C:
    def __init__(self,name):
        self.name = name
        print "C:",name

x = C("王小二")
y = C("万能的小明") # 把x覆盖了
print x.name
print y.name
测试结果如下:

__init__
C: 王小二
__call__ 王小二
C: 万能的小明
__call__ 万能的小明
万能的小明
万能的小明

从返回结果可以看出,第二个实例y把x覆盖了。

@Decorator def class C: ... 等价于C = Decorator(C),所以C就是Decorator的一个实例

x = C("王小二")就相当于x = Decorator.__call__("王小二"),该函数生成了一个原C类的一个实例,并把自己(Decorator实例)返回了。

y = C("万能的小明")又调用了Decorator.__call__函数,重新生成了原C类的一个实例,以前的实例被覆盖了。所以后面打印x.name和y.name都变成了“万能的小明”


装饰器还可以嵌套使用,如下面代码所示:

def a(f):
    return lambda: 'a' + f()

def b(f):
    return lambda: 'b' + f()

def c(f):
    return lambda: 'c' + f()

@a
@b
@c
def function():
    return "function"

print function()
返回结果为abcfunction,上面代码等于与function = a(b(c(function)))

装饰器还可以带参数

def decorator(*args):
    def wrapper(f):
        return lambda: ''.join(args) + f()
    return wrapper

@decorator('a','b','c')
def function():
    return "function"

print function()
这个代码相当于function = decorator('a','b','c')(function)

返回结果为abcfunction



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值