1.多个装饰器执行的顺序
通过一个例子来看:
def aa(f):
print("this is a~")
def wrapper(*args,**kwargs ):
print("inner a")
f(*args,**kwargs )
return wrapper
def bb(fu):
print("this is b~")
def wrapper(*args,**kwargs ):
print("inner b")
fu(*args,**kwargs)
return wrapper
@aa
@bb
def hh():
print("hh~~~~~~~~~~")
hh()
运行结果:
this is b~
this is a~
inner a
inner b
hh~~~~~~~~~~
————————————————————————————————————————
通过断点debug发现其运行路径:
开始- -> inner a -->f()但未执行hh()-->inner b-->fu()执行了hh print()-->f()-->结束
由此可得:
@aa 在函数最外部,先执行aa装饰器的装饰;接着@bb,在执行bb装饰器的装饰;执行原函数本身
————————————————————————————————————————
结论:
- 装饰顺序 : 就近原则(包装)
被装饰的函数,组装装饰器时,是从下往上装饰 - 执行顺序 : 就远原则(拆包装)
装饰器调用时是从上往下调用
运行结果中的 this is b~ this is a~ 可以理解为包装的过程来向我们print
2.多个装饰器练习
需求:[‘root’,‘admin’,‘redhat’]
id id+vip
多个装饰器的应用场景:
会采用多个装饰器先验证是否登陆成功 再验证权限是否足够
import inspect
list_root=['root','admin','redhat']
def test_login(f):
def inner(*args ,**kwargs ):
if args[0] in list_root:
res=f(*args,**kwargs )
return res
else:
print("登录失败")
return inner
def test_admin(fu):
def wrapper(*args,**kwargs): ##多个类型参数传递时;内部函数名称必须为wrapper 否则 运行到inspect模块时会报错
inspect_res = inspect.getcallargs(fu, *args, **kwargs)
print(inspect_res )
if inspect_res .get('name')=='root':
rres=fu(*args,**kwargs)
return rres
else:
print("Permission Deniy")
return wrapper
@test_login
@test_admin
def fun(user):
print("%s~~~~"%(user))
fun('admin')
运行结果:
{'user': 'admin'}
Permission Deniy