装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。在程序开发中经常使用到的功能,合理使用装饰器,能让我们的程序如虎添翼。
1 装饰器初识
装饰器本质: 就是一个 python 函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
import time
def timmer(f):
def inner():
start_time = time.time()
f()
end_time = time.time()
print('此函数的执行时间为{}'.format(end_time - start_time))
return inner
def func1():
print('in func1')
time.sleep(1)
func1 = timmer(func1)
print(func1)
func1() # 这里的func1是全新的func1,就是上面的赋值,此时相当于执行 inner函数
代码从上至下执行,执行结果:
<function timmer.<locals>.inner at 0x000001552FB00430>
in func1
此函数的执行时间为1.0000975131988525
语法: 想测试谁,前面加@装饰器函数,即可。 写装饰器,约定俗成,函数名为 wrapper
def wrapper(func):
def inner(*args, **kwargs):
'''被装饰函数之前'''
ret = func(*args, **kwargs)
'''被装饰函数之后'''
return ret
return inner
@wrapper
def func(*args, **kwargs):
print(args, kwargs)
return 666
print(func())
执行结果:
() {}
666
装饰器利用 return 制造了一个假象,func() 执行,其实是执行 inner() , func() 把原来的 func() 给覆盖了
2 装饰器传参
例 1: 上面装饰器的例子,func1,要传 2 个参数 a,b
import time
def timmer(f):
def inner(a, b):
start_time = time.time()
f(a, b)
end_time = time.time()
print('此函数的执行时间为{}'.format(end_time - start_time))
return inner
@timmer
def func1(a, b):
print('in func1 {}{}'.format(a, b))
time.sleep(1) # 模拟程序逻辑
func1(1, 2)
执行结果
in func1 12
此函数的执行时间为1.0001308917999268
例 2: 如果有多个参数呢?改成动态参数
import time
def timmer(f):
def inner(*args, **kwargs):
start_time = time.time()
f(*args, **kwargs)
end_time = time.time()
print('此函数的执行时间为{}'.format(end_time - start_time))
return inner
@timmer
def func1(*args, **kwargs):
print('in func1 {}{}'.format(args, kwargs))
time.sleep(1) # 模拟程序逻辑
func1(1, 2, a='3', b=4)
执行结果
in func1 (1, 2){'a': '3', 'b': 4}
此函数的执行时间为1.000060796737671
函数的执行时,*打散 ;
函数的定义时,*聚合。
from functools import wraps
def wrapper(f): # f = func1
def inner(*args, **kwargs): # 聚合,args (1,2,3)
'''执行函数之前的相关操作'''
ret = f(*args, **kwargs) # 打散 1,2,3
'''执行函数之后的相关操作'''
return ret
return inner
@wrapper # func1 = wrapper(func1) func1 = inner
def func1(*args): # args (1,2,3) 聚合
print(666)
return args
print(func1(*[1, 2, 3]))
执行结果:
666
(1, 2, 3)
例 3:装饰器嵌套
import time # 1.加载模块
def timmer(*args, **kwargs): # 2.加载变量 5.接收参数True,2,3
def wrapper(f): # 6.加载变量 8.f = func1
print(args, kwargs) # 9.接收timmer函数的值True,2,3
def inner(*args, **kwargs): # 10.加载变量. 13.执行函数inner
if flag: # 14 flag = True
start_time = time.time() # 15 获取当前时间
ret = f(*args, **kwargs) # 16 执行func1
time.sleep(0.3) # 19 等待0.3秒
end_time = time.time() # 20 获取当前时间
print('此函数的执行效率%f' % (end_time - start_time)) # 21 打印差值
else:
ret = f(*args, **kwargs)
return ret # 22 返回给函数调用者func1()
return inner # 11 返回给函数调用者wrapper
return wrapper # 7.返回给函数调用timmer(flag,2,3)
flag = True # 3 加载变量
@timmer(flag, 2, 3) # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)
def func1(*args, **kwargs):
return 666 # 18 返回给函数调用者f(*args,**kwargs)
print(func1()) # 12 执行函数
执行结果:
(True, 2, 3) {}
此函数的执行效率0.300905
666
写装饰器,一般嵌套 3 层就可以了
3 多个装饰器,装饰一个函数
def wrapper1(func): # func == f函数名
def inner1():
print('wrapper1 ,before func') # 2
func()
print('wrapper1 ,after func') # 4
return inner1
def wrapper2(func): # func == inner1
def inner2():
print('wrapper2 ,before func') # 1
func()
print('wrapper2 ,after func') # 5
return inner2
@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2
@wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1
def f(): # 3
print('in f')
f() # inner2()
执行结果:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
哪个离函数近,哪个先计算。 最底下的先执行
4 装饰器的 name 和 doc_
__name__:函数名
__doc___:函数的解释
4.1 普通函数
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)
"""
print(666)
func1()
print(func1.__name__) # 获取函数名
print(func1.__doc__) # 获取函数名注释说明
执行结果
666
func1
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)
这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了
4.2 带装饰器的函数
def wrapper(f): # f = func1
def inner(*args, **kwargs): # 聚合, args (1,2,3)
'''执行函数之前的相关操作'''
ret = f(*args, **kwargs) # 打散 1,2,3
'''执行函数之后的相关操作'''
return ret
return inner
@wrapper
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)
"""
print(666)
return True
func1()
print(func1.__name__)
print(func1.__doc__)
执行结果
666
inner
执行函数之前的相关操作
函数装饰之后,相当于执行了 inner 函数,所以输出 inner
为了解决这个问题,需要调用一个模块 wraps
wraps 将被修饰的函数 (wrapped) 的一些属性值赋值给修饰器函数 (wrapper) ,最终让属性的显示更符合我们的直觉
from functools import wraps
def wrapper(f): # f = func1
@wraps(f) # f是被装饰的函数
def inner(*args, **kwargs): # 聚合args (1,2,3)
'''执行函数之前的相关操作'''
ret = f(*args, **kwargs) # 打散 1,2,3
'''执行函数之后的相关操作'''
return ret
return inner
@wrapper
def func1():
"""
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)
"""
print(666)
return True
func1()
print(func1.__name__)
print(func1.__doc__)
执行结果
666
func1
此函数是完成登陆的功能,参数分别是...作用。
return: 返回值是登陆成功与否(True,False)