发现代码可以更简洁,减少重复代码和重复工作,便于维护。
在写网站的时候,许多视图函数需要做是否登录判断或者是否允许操作判断,这样每个视图函数前面都要重复一遍代码,到后期,维护是个大问题:需要找到所有函数,一个个修改。
def func():
print('我是func函数')
value = (1,2,3,)
return value
res = func()
print(res)
def func():
print('before')
print('我是func函数')
print('after')
value = (1,2,3,)
return value
func()
outer函数return inner,也就是说func = outer(func),即func=inner。
当执行func()的时候,即执行inner()。
inner里执行origin(),在inner里找不到origin,往上一层找,即outer,找到origin,origin即前面传过来的参数func,所以依然还是执行func(),执行origin()即执行func()。func函数有返回值,return res。
def outer(origin):
def inner():
res = origin()
return res
return inner
def func():
print('我是func函数')
value = (1,2,3,)
return value
func = outer(func)
res = func()
print(res)
def outer(origin):
def inner():
print('before')
res = origin()
print('after')
return res
return inner
执行结果如下:
是不是感觉结果一样,还更麻烦了?
这就是前面说的,如果量少可以直接在函数里,前后加输出。
量大再用装饰器。
@装饰器函数名
def 函数():
再func上一行加@outer 相当于 func=outer(func)
(注意:装饰器的函数要放在使用装饰器的函数之前。)
@outer
def func():
print('我是func函数')
value = (1,2,3,)
return value
res = func()
print(res)
def outer(origin):
def inner():
print('before')
res = origin()
print('after')
return res
return inner
@outer
def func():
print('我是func函数')
value = (1,2,3,)
return value
@outer
def func2():
print('我是func2函数')
value = (1,2,3,)
return value
@outer
def func3():
print('我是func3函数')
value = (1,2,3,)
return value
res = func()
res1 = func2()
res2 = func3()
上面讲的都是不带传参的函数,接下来讲带参数的。
假如,现在func有一个参数,func2有两个,func3有一个或者多个。
如果只在func函数中加入参数。
那么会报参数错误。
因为现在不仅仅是func函数的问题了,func = outer(func),现在的func = inner(),现在写的inner()没有接收参数,所以得补上,为了能接收不定个数的参数,我们用*args,**kwargs接收。
def outer(origin):
def inner(*args, **kwargs):
print('before')
res = origin(*args, **kwargs)
print('after')
return res
return inner
inner加了接收参数,但是最终还是执行的origin(),即func(),参数也不能少。
(这边inner是接收参数,origin是传参数)
def outer(origin):
def inner(*args, **kwargs):
'''inner文档注释'''
print('before')
res = origin(*args, **kwargs)
print('after')
return res
return inner
@outer
def func(a1):
'''func的文档注释'''
print('我是func函数')
value = (1,2,3,)
return value
@outer
def func2(a1,a2):
'''func2的文档注释'''
print('我是func2函数')
value = (1,2,3,)
return value
print(func.__name__)
print(func.__doc__)
print(func2.__name__)
print(func2.__doc__)
__name__是获取函数名
__doc__是获取函数文档注释
输出结果:
都是inner的函数名和文档注释。
如果希望是原来函数的函数名和注释的话,需要引入functools
在inner函数前加个@functools.wrap(传过来的函数名)。
import functools
def outer(origin):
@functools.wraps(origin) # inner.__name__=origin.__name__
def inner(*args, **kwargs):
'''inner文档注释'''
print('before')
res = origin(*args, **kwargs)
print('after')
return res
return inner
def outer(origin):
def inner(x):
for i in range(x):
origin(i)
return inner
@outer
def func(i):
print(i)
func(5)
运行结果如下:
参数:
函数:
调用func函数,就是调用inner,所以inner接收的参数即调用时的传参;
而func函数接收的参数即inner内调用origin时的传参。origin即func函数。
基本套路
def outer(origin):
def inner():
origin()
return inner
@outer
def func():
pass
理解:
可以把装饰器函数想象成一个框架,可以往里面嵌入不同的功能,这个嵌入的功能即被装饰的函数。像龙骑的腰带,是通用的,往里面放入不同的卡盒,就是不同的骑士了。而腰带就是装饰器,卡盒是被装饰的函数。
例如:占位符,string = f’this is {xxx}’ ,string就是装饰器,{xxx}占位符就是被装饰的函数。
实际应用:例如每个函数前面都需要进行一个对消息队列的读取操作,就可以把读取操作写在装饰器inner内,然后将具体业务逻辑函数放在读取之后的操作,将读取的结果当作参数传给业务逻辑函数。