def w1(func):
def inner():
# 验证1
# 验证2
# 验证3
func()
return inner
@w1
def f1():
print('f1')
python解释器就会从上到下解释代码,步骤如下:
def w1(func): ==>将w1函数加载到内存
@w1
没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。
从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章, @函数名 是python的一种语法糖。
上例@w1内部会执行一下操作:
执行w1函数
执行w1函数 ,并将 @w1 下面的函数作为w1函数的参数,即:@w1 等价于 w1(f1) 所以,内部就会去执行:
def inner():
#验证 1
#验证 2
#验证 3
f1() # func是参数,此时 func 等于 f1
return inner# 返回的 inner,inner代表的是函数,非执行函数 ,其实就是将原来的 f1 函数塞进另外一个函数中
w1的返回值
将执行完的w1函数返回值 赋值 给@w1下面的函数的函数名f1 即将w1的返回值再重新赋值给 f1,即:
新f1 = def inner():
#验证 1
#验证 2
#验证 3
原来f1()
return inner
所以,以后想要执行 f1 函数时,就会执行 新f1 函数,在新f1 函数内部先执行验证,再执行原来的f1函数,然后将原来f1 函数的返回值返回给了业务调用者。
例如
# 定义函数:完成包裹数据
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
# 定义函数:完成包裹数据
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())
运行结果
<b>hello world-1</b>
<i>hello world-2</i>
<b><i>hello world-3</i></b>
装饰器的功能
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
装饰器示例
被装饰的函数没有参数
from time import ctime, sleep
def demofun(func):
def wrapped_func():
print("%s called at %s" % (func.__name__, ctime()))
func()
return wrapped_func
@demofun
def demo1():
print("I am foo")
demo1()
sleep(2)
demo1()
上面代码理解装饰器执行行为可理解成
demo1= demofun(demo1)
# demo1先作为参数赋值给func后,demo1接收指向demofun返回的wrapped_func
demo1()
# 调用demo1(),即等价调用wrapped_func()
# 内部函数wrapped_func被引用,所以外部函数的func变量(自由变量)并没有释放
# func里保存的是原demo1函数对象
被装饰的函数有参数
from time import ctime, sleep
def demofun(func):
def wrapped_func(a, b):
print("%s called at %s" % (func.__name__, ctime()))
print(a, b)
func(a, b)
return wrapped_func
@demofun
def demo1(a, b):
print(a+b)
demo1(3,5)
sleep(2)
demo1(2,4)
被装饰的函数有不定长参数
from time import ctime, sleep
def demofun(func):
def wrapped_func(*args, **kwargs):
print("%s called at %s"%(func.__name__, ctime()))
func(*args, **kwargs)
return wrapped_func
@demofun
def demo1(a, b, c):
print(a+b+c)
demo1(3,5,7)
sleep(2)
demo1(2,4,9)
装饰器中的return
from time import ctime, sleep
def demofun(func):
def wrapped_func():
print("%s called at %s" % (func.__name__, ctime()))
func()
return wrapped_func
@demofun
def demo1():
print("I am demo1")
@demofun
def demo2():
return '----hahah---'
demo1()
sleep(2)
demo1()
print(demo2())
执行结果
demo1 called at Fri Nov 4 21:55:35 2016
I am demo1
demo1 called at Fri Nov 4 21:55:37 2016
I am demo1
demo2 called at Fri Nov 4 21:55:37 2016
None
如果修改装饰器为return func(),则运行结果:
demo1 called at Fri Nov 4 21:55:57 2016
I am demo1
demo1 called at Fri Nov 4 21:55:59 2016
I am demo1
demo2 called at Fri Nov 4 21:55:59 2016
----hahah---
一般情况下为了让装饰器更通用,可以有return