有参装饰器

wraps装饰器补充
偷梁换柱:即将原函数名(index)指向的内存地址偷梁换柱成wrapper,所以应该将wrapper做的跟原函数一样
(1)
def index(x,y):
'''这个是主页功能'''
print(x,y)
index(1,2)

print(index.__name__) # index
print(help(index))
help运行结果:
Help on function index in module __main__:
index(x, y)
这个是主页功能

(2)
def outter(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper

根据账号密码不同来源验证登录:
问题:需要传入参数db_type,而装饰器的outter函数只能传入被装饰对象函数地址一个参数
low解决方法:
def deco(func,db_type):
def wrapper(*args,**kwargs):
name = input('your name:').strip()
pswd = input('your password:').strip()
if db_type == 'file':
print('基于文件的验证')
if name == 'lili' and pswd == '1234':
res = func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type == 'mysql':
print('基于mysql的验证')
elif db_type == 'ldap':
print('基于ldap的验证')
else:
print('不支持该db_type')
return wrapper

def index(x,y):
print('index %s %s'%(x,y))

def home(name):
print('home %s'%name)

def transfer():
print('transfer')

index = deco(index,'file')
home = deco(home,'mysql')
transfer = deco(transfer,'ldap')

index(11,22)
home('lili')
transfer()

@outter
def index(x,y):
'''这个是主页功能'''
print(x,y)
index(1,2)

print(index.__name__) # wrapper
print(help(index)) help(index) 相当于 index.__doc__
help查看注释信息运行结果:
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)

以上情况对比发现:加入装饰器后的index函数与原先的index函数的一些属性上是发生了改变的,并不是真正的原始的index

解决方案:
from functools import wraps 导入
def outter(func):
@wraps(func) # 将func的所有属性赋值给wrapper
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper

@outter
def index(x,y):
'''这个是主页功能'''
print(x,y)
index(1,2)

print(index.__name__) # index
print(index.__doc__) # 这个是主页功能
这一步骤是更加细化装饰过程,使装饰后的index与原始index返回值、属性等一致

 

外层包一个函数用于传参db_type
分析:
def auth(db_type):
def deco(func):
.....
return deco
deco = auth(db_type = 'file')

@deco
def index(x,y):
print('index %s %s'%(x,y))
@deco
def home(name):
print('home %s'%name)
@deco
def transfer():
print('transfer')

index(11,22)
home('lili')
transfer()
结果三者来源都为file,而没有区分出基于mysql和ldap的验证

优化:
def auth(db_type):
def deco(func):
def wrapper(*args,**kwargs):
name = input('your name:').strip()
pswd = input('your password:').strip()
if db_type == 'file':
print('基于文件的验证')
if name == 'lili' and pswd == '1234':
res = func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type == 'mysql':
print('基于mysql的验证')
elif db_type == 'ldap':
print('基于ldap的验证')
else:
print('不支持该db_type')
return wrapper
return deco

@auth(db_type='file')
def index(x,y):
print('index %s %s'%(x,y))

@auth(db_type='mysql')
def home(name):
print('home %s'%name)

@auth(db_type='ldap')
def transfer():
print('transfer')

index(1,22) # wrapper(1,22)
home('lili') # wrapper('lili')
transfer()

一个函数多个装饰器

def decorator_a(func):
print('this is decorator_a')
def inner_a(*args,**kwargs):
print('this is inner_a')
return func(*args,**kwargs)
return inner_a

def decorator_b(func):
print('this is decorator_b')
def inner_b(*args,**kwargs):
print('this is inner_b')
return func(*args,**kwargs)
return inner_b

@decorator_b
@decorator_a
def f(x):
print('this is f')
return x*2
f(1)

运行结果:
this is decorator_a
this is decorator_b
this is inner_b
this is inner_a
this is f
程序开始执行decorator函数内部的内容,一开始它又碰到了一个函数inner,inner函数定义块被程序观察到后不会立刻执行,而是读入内存中(这是默认规则)

- 就近原则
- 说明装饰器函数在被装饰函数定义好后就立即执行。
- 而且执行顺序是由下到上开始装饰。调用decorator_a时,f被装饰成inner_a,调用decorator_b时,f被装饰成inner_b。因此,装饰顺序是”就近原则“

— 就远原则
- 通过打印f发现,f最终被装饰成了()。
- 而inner_b中return的func,实则为inner_a, inner_a中return的func才是最终的f,所以最后的调用顺序为inner_b --->inner_a--->f。因此执行顺序为”就远原则“

有参装饰器总结:
from functools import wraps
def 有参装饰器(x,y,z):
def outter(func):
@wraps(func) # 将func的所有属性赋给wrapper
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
return outter

@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass
被装饰对象()

posted @ 2021-09-10 15:36  多啦a梦与时光机  阅读(62)  评论(0编辑  收藏  举报