发布时间:2019-08-06 13:56:23编辑:auto阅读(1392)
装饰器(无参)
它是一个函数;
函数作为它的形参;
返回值也是一个函数;
可以使用@functionname方式,简化调用;
装饰器和高阶函数
装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)
import datetime import time def logger(fn): def wrap(*args, **kwargs): #before 功能增强 print("args={},kwargs={}".format(args, kwargs)) start = datetime.datetime.now() ret = fn(*args, **kwargs) #after 功能增强 duration = datetime.datetime.now() - start print("function {} took {}s.".format(fn.__name__, duration.total_seconds())) return ret return wrap @logger def add(x, y): print("======call add======") time.sleep(2) return x + y print(add(4, y=5))
讲一个新的小知识点---文档字符串
python的文档
python是文档字符串Documentation Strings
在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号;
惯例是首字母大写,第一行写概述,空一行,第三行写详细描述;
可以使用特殊属性__doc__访问这个文档
def add(x, y): """This is a function of addition""" a = x + y return x + y print("name={}\ndoc={}".format(add.__name__, add.__doc__)) print(help(add))
这就是文档字符串,通过文档字符串可以查看这个函数的帮助等一些信息
我们在来看一段代码,它的输出结果是什么呢?
import datetime import time def logger(fn): def wrap(*args, **kwargs): """This is a wrapper""" #before 功能增强 print("args={},kwargs={}".format(args, kwargs)) start = datetime.datetime.now() ret = fn(*args, **kwargs) #after 功能增强 duration = datetime.datetime.now() - start print("function {} took {}s.".format(fn.__name__, duration.total_seconds())) return ret return wrap @logger def add(x, y): """This is a function""" print("======call add======") time.sleep(2) return x + y # print(add(4, y=5)) print(add.__name__, add.__doc__,sep='\n')
运行结果如下:
wrap
This is a wrapper
通过代码也能看出来,使用装饰器是有副作用的:
原函数对象的属性都被替换了,而使用装饰器,我们的需求是查看被封装函数的属性,如何解决?
想一下,这个函数的调用为什么要写到79行???插入到其它行,行不行?这个自己考虑想想吧,这里就不提了。
既然我们学会了装饰器,那如何把copy_properties改造成装饰器?这就引出了我们的带参装饰器
import datetime import time def copy_properties(src): def wrapper(dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ dst.__qualname__ = src.__qualname__ return dst return wrapper def logger(fn): @copy_properties(fn)# copy_properties.wrapper(logger.wrap), def wrap(*args, **kwargs): """This is a wrapper""" #before 功能增强 print("args={},kwargs={}".format(args, kwargs)) start = datetime.datetime.now() ret = fn(*args, **kwargs) #after 功能增强 duration = datetime.datetime.now() - start print("function {} took {}s.".format(fn.__name__, duration.total_seconds())) return ret return wrap @logger def add(x, y): """This is a function""" print("======call add======") time.sleep(2) return x + y # print(add(4, y=5)) print(add.__name__, add.__doc__, add.__qualname__, sep='\n')
通过copy_properties函数将包装函数的属性覆盖掉包包装函数;
凡是被装饰的函数都需要复制这些属性,这个函数很通用;
可以将复制属性的函数构建成装饰器函数,带参装饰器;
需求:获取函数的执行时长,对时长超过阈值的函数记录一下:
import datetime import time def logger(t):# def logger(t1, t2, t3....tn): def _logger(fn): #@copy_properties(fn) 可以把上面写的复制属性的函数装饰在此 def wrap(*args, **kwargs): #before 功能增强 # print("args={},kwargs={}".format(args, kwargs)) start = datetime.datetime.now() ret = fn(*args, **kwargs) #after 功能增强 duration = (datetime.datetime.now() - start).total_seconds() if duration > t: print("function {} took {}s.".format(fn.__name__, duration)) return ret return wrap return _logger @logger(3)# add = logger(3)(add), @logger(3, 5, 9,...n) def add(x, y): print("======call add======") time.sleep(5) return x + y print(add(4, y=5))
装饰器(带参)
它是一个函数;
函数作为它的形参;
返回值是一个不带参的装饰器函数;
使用@functionname(参数列表)方式调用;
可以看做在装饰器外层又加了一层函数;
将记录的功能提取出来,这样就可以通过外部提供的函数来灵活的控制输出:
def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))): def _logger(fn): @copy_properties(fn): def wrapper(*args, **kwargs): start = datetime.datetime.now() ret = fn(*args, **kwargs) delta = (datetime.datetime.now() - start).total_seconds() if delta > duration: func(fn.__name__, duration) return ret return wrapper return _logger
上一篇: Cent OS7安装Python 2.7
下一篇: Python之石头剪刀布
47494
45795
36793
34325
28968
25598
24443
19611
19111
17633
5466°
6048°
5570°
5638°
6573°
5376°
5378°
5885°
5855°
7171°