上篇中我们介绍了闭包的用法,同时利用装饰器实现了为函数添加返回原始数据的功能,那么它是如何实现的呢,让我们一起来揭开它神秘的面纱。
def decorator(f):
def wrapper(x,y):
print("参数1为:%s,参数2为:%s"%(x,y))
return f(x,y)
return wrapper
@decorator
def add(x,y):
return x+y
print(add(2,3))
解析:本质上装饰器就是一个返回函数的高阶函数,它接收一个函数,并返回一个函数,用法就是在被装饰的函数上面加上@装饰器函数名。此时,把@decorator 放到add函数的定义处,相当于执行了 add = decorator(add),结果就是返回了一个函数对象wrapper,wrapper后加上(x,y),然后执行装饰器函数内部定义的wrapper()函数。此时函数的指向发生了变化,让我们看下面的代码:
def decorator(f):
def wrapper(x,y):
print("参数1为:%s,参数2为:%s"%(x,y),f.__name__)
return f(x,y)
return wrapper
@decorator
def add(x,y):
print(add.__name__)
return x+y
print(add(2,3))
执行结果:
参数1为:2,参数2为:3 add
wrapper
5
解析:在add函数前加上@decorator,执行了decorator(add)函数,add代表传入的形参f,返回的wrapper指向了原有的add位置,新的add函数名字发生了改变。所以,我们可以使用python的functools模块把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。在这之上我们还可以再添加一个函数,输出一些参数。
import functools
def log(text):
def decorator(f):
@functools.wraps(f)
def wrapper(x,y):
print(text,"参数1为:%s,参数2为:%s"%(x,y),f.__name__)
return f(x,y)
return wrapper
return decorator
@log("python之装饰器")
def add(x,y):
print(add.__name__)
return x+y
print(add(2,3))
执行结果:
python之装饰器 参数1为:2,参数2为:3 add
add
5
解析:加上@functools.wraps(f)后,新的add()函数的名字还是原来的add,我们添加了log函数,传入了一串字符,函数执行时可以打印出来。
总结:装饰器能够将一个函数的功能在不修改代码的情况下进行扩展,在函数定义的上方@装饰器函数名 即可直接使用装饰器对下面的函数进行装饰。
类装饰器
接下来我们用面对对象的方法实现装饰器的功能,你应该有python面对对象编程的基础,这里面会用到魔法方法。
<1>
class Decrator(object):
def __init__(self,fn):
print("初始化函数",fn.__name__)
self._func = fn
def __call__(self,*args):
print("打印的内容",*args)
return self._func(*args)
@Decrator
def sum(x,y):
print(sum)
return x+y
print(sum(3,3))
执行结果
初始化函数 sum
打印的内容 3 3
<__main__.Decrator object at 0x0000024986FF7198>
6
解析:函数sum定义前加上@Decorator,相当于实例化类对象Decorator(sum),同时初始化实例属性self._func=sum函数;接下来实例对象后加上(),会调用实例对象的__call__方法,打印出内容和参数,然后返回实例属性即sum函数并执行函数计算x+y。