内容纯属个人理解,不对之处,欢迎指正。
之前说过,装饰器其实就是函数,既然是函数,那就可以有参数,装饰器也不例外,接下来我们来分析带参数的装饰器。
如何构造带参数
带参数倒是很简单,在装饰的时候给装饰函数写上参数就行,但是具体的装饰器函数该怎么写,我们需要思考一下。
我们想让它带参数,无非就是对被装饰函数的执行进行一定条件的限定设置,也就是说在函数执行之前,函数就必须具备这个条件,那么这样的话,就有两种选择,要么在传递func以后传递参数;要么在传递func之前传递参数。
在想法上,两种其实是都可以的,但是,我们传递参数的时候是给装饰器传递,也就是说,装饰器函数首先接收的是装饰器函数的参数,然后带着这个参数再去装饰函数。因此,我们就必须先处理装饰器函数的参数,然后再去处理被装饰的函数。
所以在实现上,我们应该这样去构造带参装饰器函数:
def deco_para(parameter):
def deco_func(func):
def wrapper(*args, **kwargs):
print(parameter)
func(*args, **kwargs)
return wrapper
return deco_func
带参装饰器示例
def deco_para(parameter):
print('enter deco_para')
def deco_func(func):
print('enter deco_func')
def wrapper(*args, **kwargs):
print('enter wrapper')
print(parameter)
print('---wrapper: before func---')
func(*args, **kwargs)
print('---wrapper: after func---')
return wrapper
return deco_func
@deco_para(123)
def foo():
print('---foo---')
if __name__ == '__main__':
print('--start--')
foo()
运行结果:
enter deco_para
enter deco_func
--start--
enter wrapper
123
---wrapper: before func---
---foo---
---wrapper: after func---
结果应该不用多说,先接收参数123,然后接收函数foo,最后执行wrapper。
装饰过程解析--多次输出问题
我们解析下过程
deco_func = deco_para(123) # 接收参数123
wrapper = deco_func(foo) # 接收函数foo
foo = wrapper # 重命名
foo() # 执行foo
如果你试着按这个过程去执行代码,会发现一个问题,wrapper函数里面的代码执行了2次。
enter deco_para
enter deco_func
enter deco_para
enter deco_func
enter wrapper
123
---wrapper: before func---
enter wrapper
123
---wrapper: before func---
---foo---
---wrapper: after func---
---wrapper: after func---
我们看下究竟是怎么回事。
# 程序执行,扫面到装饰器,执行装饰器函数内部代码
1.enter deco_para
2.enter deco_func
# deco_para(123)接收参数123时执行3
3.enter deco_para
# deco_func(foo)接收函数foo时执行4
4.enter deco_func
# foo()执行foo()
5.enter wrapper
6.123
7.---wrapper: before func---
8.enter wrapper
9.123
10.---wrapper: before func---
11.---foo---
12.---wrapper: after func---
13.---wrapper: after func---
在之前解析装饰器的时候就提到过,函数被装饰以后,就不是原来的函数了,也就是说上面所执行的foo,其实是wrapper。
那么wrapper里面有什么东西呢?
print('enter wrapper')
print(parameter)
print('---wrapper: before func---')
func(*args, **kwargs)
print('---wrapper: after func---')
似乎执行结果应该是
enter wrapper
123
---wrapper: before func---
---foo---
---wrapper: after func---
但是事实上,此时的wrapper里面的func已经不是原来的func。
回顾闭包:引用了自由变量的函数即是一个闭包,这个被引用的自由变量和这个函数一同存在, 即使已经离开了了创造它的环境也不例外。
那么可以推测,此时的被装饰函数应该具有了额外的东西,这些东西就是
print('enter wrapper')
print(parameter)
print('---wrapper: before func---')
print('---wrapper: after func---')
由此也就可以知道为什么wrapper里面的代码执行了2次:就是在执行到func(*args, **kwargs)的时候,执行了功能丰富以后的func。
网友评论