python 装饰器
示例介绍
-
什么是装饰器:
定义一个新的函数使原函数作为该函数的参数,新函数内部返回一个对原函数业务逻辑处理的装饰作用的函数。装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能,拓展原来函数功能的一种函数,其本质就是早于被装饰的函数执行,比如在权限认证装饰器内部判断是否符合相应的权限,符合权限则继续执行原函数,不符合则不调用原函数,终止执行。
-
装饰器的使用场景:
身份认证、权限认证、日志记录、输入合理性检查等
-
什么样的语言可以使用装饰器?
函数可以作为参数传递的语言,可以使用装饰器
先上一个简单demo
def auth(func):
def wrapper(*args, **kwargs):
name = args[0]
pwd = args[1]
if name == 'zhangsan' and pwd == '123':
return func(*args, **kwargs)
return '账号密码错误请重新登录'
return wrapper
# --------------------------------------------------------------------------------------
@auth # 效果等同于 add_to_shopping_cart = auth(add_to_shopping_cart)
def add_to_shopping_cart(username, pwd):
print(username, pwd)
print('正在将商品加入购物车......')
return '商品加入购物车成功了'
res = add_to_shopping_cart('zhangsan', '12m3')
print(res)
#以上代码相当于如下代码
# def add_to_shopping_cart(username, pwd):
# print('正在将商品加入购物车......')
# return '商品加入购物车成功了'
# add_to_shopping_cart = auth(add_to_shopping_cart)
# res = add_to_shopping_cart('zhangsan', '123')
# print(res)
带参数的装饰器
def wrapper_out(needed_permission):
def auth(func):
def wrapper(*args, **kwargs):
name = args[0]
pwd = args[1]
role = args[2]
if name == 'zhangsan' and pwd == '123':
# 不但验证账户密码,并且验证权限(只有admin或teacher身份才能将商品加入购物车)
if role not in needed_permission.split('|'): # 验证权限
return "你没有权限,只有老师或管理员才有权限"
return func(*args, **kwargs)
else:
return '账号密码错误请重新登录'
return wrapper
return auth
@wrapper_out('admin|teacher')
def add_to_shopping_cart(username, pwd, role):
print(username, pwd, role)
print('正在将商品加入购物车......')
return '商品加入购物车成功了'
res = add_to_shopping_cart('zhangsan', '123', 'teacher')
print(res)
-
以上带参数的装饰器其实最外层就是一个普通的函数
-
@wrapper_out(‘admin|teacher’) 过程解读:
函数执行到带参数装饰器 @wrapper_out(‘admin|teacher’) 执行分两步:
1.执行wrapper_out(‘admin|teacher’)这个函数,把相应的参数’admin|teacher’传给needed_permission,并且得到返回值auth函数名
2.将@与auth结合,得到我们之前熟悉的标准版的装饰器,按照装饰器的执行流程执行。
functools中的wraps
- 在使用装饰器的过程中有没有发现被装饰后的函数其实已经是另外一个函数了,比如上面的示例我最终期望装饰后的函数包括其函数名、函数属性、内存地址应该是关于add_to_shopping_cart这个函数的相关,而现实是被装饰的函数已变为auth这个函数的相关,为了解决这个问题我们使用functools中的wraps
def auth(func):
def wrapper(*args, **kwargs):
name = args[0]
pwd = args[1]
if name == 'zhangsan' and pwd == '123':
return func(*args, **kwargs)
return '账号密码错误请重新登录'
return wrapper
@auth
def add_to_shopping_cart(username, pwd):
print(username, pwd)
print('正在将商品加入购物车......')
return '商品加入购物车成功了'
print(add_to_shopping_cart) # 已经是另外一个函数了 <function auth.<locals>.wrapper at
# 0x000001D26E909160>
# ----------------------------------------------------------------------------------------
from functools import wraps
def auth(func):
@wraps(func)
def wrapper(*args, **kwargs):
name = args[0]
pwd = args[1]
if name == 'zhangsan' and pwd == '123':
return func(*args, **kwargs)
return '账号密码错误请重新登录'
return wrapper
@auth
def add_to_shopping_cart(username, pwd):
print(username, pwd)
print('正在将商品加入购物车......')
return '商品加入购物车成功了'
print(add_to_shopping_cart) # 加了wraps之后就是最初期望的样子了<function add_to_shopping_cart at 0x00000200E54374C0>