1、定义:在不改变原函数的调用以及内部代码的情况下,为其添加新功能的函数。
2、装饰器的逻辑推导
def func01():
print("func01执行了")
def print_func_name(func):
def wrapper():
# 新功能
print(func.__name__)
# 旧功能
func()
return wrapper
func01 = print_func_name(func01) # 此时:func01==wrapper
func01() # 执行的是内部函数wrapper()
# 输出:
func01
func01执行了
当函数func01()有返回值时:
def func01():
print("func01执行了")
return "ok"
def print_func_name(func):
def wrapper():
# 新功能
print(func.__name__)
# 旧功能
func()
return wrapper
func01 = print_func_name(func01) # 此时,func01==wrapper
func01() # 执行的是内部函数wrapper()
print(func01()) # 即:print(wrapper()),而wrapper没有返回值,所以下面输出最后返回None
# 输出:
func01
func01执行了
None
上面代码中,由于我们写了func01=print_func_name(func01),而print_func_name的返回值是wrapper,所以func01==wrapper,我们在调用func01()时,其实调用的是wrapper()了,不再是顶上的func01(),它等于是被拦截了(装饰器的核心思想就是拦截),而wrapper函数没有返回值,所以输出为None。如果想输出ok,应该把wrapper函数中的func()改为return func()。代码如下:
def func01():
print("func01执行了")
return "ok"
def print_func_name(func):
def wrapper():
# 新功能
print(func.__name__)
# 旧功能
return func()
return wrapper
func01 = print_func_name(func01) # 即:func01==wrapper,因为print_func_name返回值是wrapper
func01() # 即:执行wrapper(),执行print(func.__name__)
print(func01()) # 相当于print(wrapper()),即:print(func01()旧功能),故输出ok
# 输出:
func01
func01执行了
ok
当有func01()和func02()两个函数时,且func2()有参数,而func01()没有参数:
最后,光有*args还不够,因为*args只能搞定位置实参,还要有**kwargs来搞定关键字实参。下面的代码就是完整的装饰器推导了
练习:在不改变原有功能的定义与调用情况下(进入后台,删除订单),为其增加新功能(验证权限)
def enter_background():
print("进入后台")
def delete_order():
print("删除订单")
def verify_permissions(func):
def wrapper(*args, **kwargs):
# 新功能
print("验证权限")
# 旧功能
return func(*args, **kwargs)
return wrapper
enter_background = verify_permissions(enter_background)
enter_background()
delete_order = verify_permissions(delete_order)
delete_order()
# 输出:
验证权限
进入后台
验证权限
删除订单
以上只是装饰器的推导原理,在真实的Python中,装饰器不是像上面这样写的,应该是这样:
def print_func_name(func):
def wrapper(*args, **kwargs):
# 新功能
print(func.__name__)
# 旧功能
return func(*args, **kwargs)
return wrapper
@print_func_name # 内部原理其实就是:func01 = print_func_name(func01)
def func01():
print("func01执行了")
return "ok"
@print_func_name # 内部原理其实就是:func02 = print_func_name(func02)
def func02(a):
print(a, "func02执行了")
# func01 = print_func_name(func01) # 不需要了
print(func01())
# func02 = print_func_name(func02) # 不需要了
print(func02(100))
装饰器的作用:
可能一个函数我们今天想给它增加一个功能A,但是明天我们想把功能A给换成功能B,那么如果把这些新增的功能直接写在函数内然后再改来改去就很麻烦,所以我们可以用装饰器来完成这些操作。