看完(一)后,想必已经对装饰器有了一个基本的概念。在(二)中,我将会对装饰器的一些高级用法做一点研究记录。
1、装饰器带其他参数
接着上面的例子,我们希望并不是每个人都有权限去使用这个计算函数,只有特定的人才可以。
def checktype(personname=None):
def decorate(func):
def wrapper(*args,**kwargs):
count = 0
if personname == 'ghy':
str = []
for n in args:
if not isinstance(n,(int,float)):
log= '{}的类型无法计算'.format(n)
str.append(log)
count += 1
if count == 0:
return func(*args,**kwargs)
else:
print(str)
else:
print('{}, you are limited'.format(personname))
return wrapper
return decorate
@checktype('test')
def calfunc(*numbers,sign=None):
if sign is None:
return 'please input a sign'
if hasattr(case['+'], '__call__'):
add=case['+']
return print(add(*numbers))
#调用
calfunc('a','b',sign='+') #输出 test you are limited
2、自定义装饰器属性
有时候我们会想通过为装饰器定义一些属性,来修改其中的参数
如上个例子所示,我们想通过属性来修改personname的值
from functools import wraps,partial
#将函数属性附加到包装函数上
#使用partial函数
#from functools import partial
#partial 函数的作用就是
#把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
#第一个参数为原函数。
def add_attr(obj,func=None):
if func is None:
return partial(add_attr,obj)
setattr(obj,func.__name__,func)
return func
#装饰器
def checktype(personname=None):
def decorate(func):
#保留原函数的一些元数据 比如 函数名 不加 calfunc.__name__输出 wrapper
@wraps(func)
def wrapper(*args,**kwargs):
count = 0
if personname == 'ghy':
str = []
for n in args:
if not isinstance(n,(int,float)):
log= '{}的类型无法计算'.format(n)
str.append(log)
count += 1
if count == 0:
return func(*args,**kwargs)
else:
print(str)
else:
print('{}, you are limited'.format(personname))
@add_attr(wrapper) #相当于 add_attr(wrapper)()=>add_attr(wrapper,sef_modifypersonname)
def sef_modifypersonname(newname):
nonlocal personname # 如果没有这个,下面一句是在当前作用域内又创建了一个personame
personname = newname
return wrapper
return decorate
@checktype('test')
def calfunc(*numbers,sign=None):
if sign is None:
return 'please input a sign'
if hasattr(case['+'], '__call__'):
add=case['+']
return print(add(*numbers))
calfunc(1,2,sign='+') #输出 test you are limited
calfunc.sef_modifypersonname('ghy')
calfunc(1,2,sign='+') #输出 3
#装饰器解包,调用__wrapped__ 不进入装饰器包装函数
calfunc.sef_modifypersonname('test')
calfunc.__wrapped__(1,2,sign='+') #输出 3
上面一个比较重要的稍微难以理解的点就是@add_attr(wrapper),但其实你只要明白了
装饰器是在代码解释的时候就已经调用执行了
也就是说我们的装饰器处的代码,我们可以心里自动给它默认为
sef_modifypersonname=add_attr(wrapper)(sef_modifypersonname)
还有一个即 @wraps(func)注释已经写的很清楚了,保留原函数的元数据。