python装饰器本质上就是闭包。所谓闭包,指的是这样一类函数,其返回值是定义在其内部的另一个函数,如下例:
def outer(a):
# 定义一个内函数inner
def inner(b=10):
#在内函数中 用到了外函数的临时变量a
print('a + b = ',a+b)
return a+b
# 外函数的返回值是内函数的引用
return inner
对于一个具有装饰功能的闭包函数,假设仍取名为outer,其参数a应该被理解为一个函数对象,也就是待装饰的目标函数,为了便于理解,修改上面的代码如下:
def f1(c=0):
print('the value is ',c)
def outer(func):
a1=1
# 定义一个内函数inner
def inner(b=10):
# 这个func就是要装饰的目标函数,outer函数内部并没有对它做修改
# 只是将之放到了outer函数内部执行而已
func()
print('a1 + b = ',a1+b)
return a1+b
# 外函数的返回值是内函数的引用
return inner
f2 = outer(f1)
f2()
#输出结果为
>>>the value is 0
>>>a1 + b = 11
要装饰的目标函数也可以先引用后定义,如上事实上已经实现了一个装饰器函数的功能,现加入语法糖@对其进行改造:
def outer(func):
a1=1
# 定义一个内函数inner
def inner(b=10):
# 这个func就是要装饰的目标函数,outer函数内部并没有对它做修改
# 只是将之放到了outer函数内部执行而已
func()
print('a1 + b = ',a1+b)
return a1+b
# 外函数的返回值是内函数的引用
return inner
@outer
def f1(c=0):
print('the value is ',c)
f1()
#输出结果为
>>>the value is 0
>>>a1 + b = 11
如上就是装饰器的工作原理,此时如果去查f1函数的名称,会发现它已经不是它本身了:
f1.__name__
# 输出结果为
>>>inner
如果不做处理,以后调用f1函数,实际上就是调用定义在outer里面的inner函数,为了能够使f1函数仍旧保持其独立性,可以引入functools 的@wraps:
from functools import wraps
def outer(func):
a1=1
# wraps本身也是一个装饰器,提供拷贝功能
@wraps(func)
def inner(b=10):
# 这个func就是要装饰的目标函数,outer函数内部并没有对它做修改
# 只是将之放到了outer函数内部执行而已
func()
print('a1 + b = ',a1+b)
return a1+b
# 外函数的返回值是内函数的引用
return inner
@outer
def f1(c=0):
print('the value is ',c)
f1()
#输出结果为
>>>the value is 0
>>>a1 + b = 11
f1.__name__
# 输出结果为
>>>f1
所谓带参数的装饰器,则是在闭包上再加一层闭包:
def outer2(d):
def outer1(func):
a1=1
# wraps本身也是一个装饰器
@wraps(func)
def inner(b=10):
# 这个func就是要装饰的目标函数,outer函数内部并没有对它做修改
# 只是将之放到了outer函数内部执行而已
func(d)
print('a1 + b = ',a1+b)
return a1+b
# 外函数的返回值是内函数的引用
return inner
return outer1
@outer2(100)
def f1(c):
print('the value is ',c)
f1(1)
至于通过类来实现装饰功能,待以后有时间再整理更新。感谢阅读。