携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
0 环境
- 编辑器:idea或vscode
- 系统版本:windows10
- python版本:3.9.6
1 装饰器的副作用
import datetime
import time
def logger1(fn):
def wrap(*args, **kwargs):
print("sleep.__name__ -->", sleep.__name__)
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
end = datetime.datetime.now()
print("{} called took {}".format(fn.__name__, end - start))
return ret
return wrap
@logger1
def sleep(val):
time.sleep(val)
if __name__ == '__main__':
sleep(1)
当我用把装饰器装到sleep函数上后,使用sleep函数后,它的__name__的值,竟然是wrap,而且无论我放在装饰器中,还是sleep函数中都是这个结果。怎样修改呢,如下代码:添加了一个async_properties函数,并且为其重新赋值。这样我们的原函数都能知道它的名字和doc了。
def logger1(fn):
def wrap(*args, **kwargs):
print("sleep.__name__ -->", sleep.__name__)
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
end = datetime.datetime.now()
print("{} called took {}".format(fn.__name__, end - start))
return ret
async_properties(fn, wrap)
return wrap
def async_properties(source, target):
target.__name__ = source.__name__
target.__doc__ = source.__doc__
2 柯里化
柯里化就是这样子的,是不是看着很眼熟,一股浓浓的装饰器的味道,确实返回的是一个装饰器。
def async_properties1(source):
def _assign(target):
target.__name__ = source.__name__
target.__doc__ = source.__doc__
return target
return _assign
改造我们的代码,如下代码:
def logger1(fn):
@async_properties1(fn)
def wrap(*args, **kwargs):
print("sleep.__name__ -->", sleep.__name__)
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
end = datetime.datetime.now()
print("{} called took {}".format(fn.__name__, end - start))
return ret
# async_properties(fn, wrap)
return wrap
def async_properties1(source):
def _assign(target):
target.__name__ = source.__name__
target.__doc__ = source.__doc__
return target
return _assign
看到最终的结果是不是就能猜到是说的带参数的装饰器了。
2 总结
肯定会疑问柯里化(带参数的装饰器)和之前安装在要使用装饰器的函数的区别是吧,为啥之前那种方式sleep上面@xxxx不需要传参,而现在需要传参,仅个人理解哈,就是之前的那种不需要传参的方式,logger1最外层的参数就是sleep,直接帮我们把sleep传过去了,而本来是在wrap函数下调用async_properties1(fn)(wrap),现在用柯里化的方式@async_properties1(fn),反而缺少了wrap函数的代入,盲猜它把wrap自动代入进入了。当然这里的wrap,要放在最后,有点关键字的味道了,不然打印结果的是控制台无任何输出。