
Python:函数 ----》装饰器函数
发布日期:2021-05-07 14:08:01
浏览次数:7
分类:原创文章
本文共 4755 字,大约阅读时间需要 15 分钟。
目录
引入
一个加法函数,想增强它的功能,能够输出被调用过以及调用的参数信息
def add(x, y): return x + y
用嵌套函数、柯里化来解决
def add(x,y): return x + ydef logger(fn): def _loger(*args,**kwargs): print("函数开始运行") ret = fn(*args,**kwargs) print("函数结束") return ret return _logerprint(logger(add)(10,40))
在变形【这就是装饰器函数,侵入式代码】
- 装饰器语法糖
def logger(fn): def _loger(*args,**kwargs): print("函数开始运行") ret = fn(*args,**kwargs) print("函数结束") return ret return _loger@logger #等价于 add1 = logger(add1) def add1(x,y): return x + y#add1 = logger(add1) print(add1(5,10))
装饰器【无参】
装饰器(无参)
- 它是一个函数
- 函数作为它的形参
- 返回值也是一个函数
- 可以使用@functionname方式,简化调用方式
装饰器和高阶函数
- 装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)
文档字符串
Python的文档
- Python是文档字符串Documentation Strings
- 在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号
- 惯例是首字母大写,第一行写概述,空一行,第三行写详细描述
- 可以使用特殊属性__doc__访问这个文档
只能放在番薯的第一行,否则无法获取到,显示为None
def add(x,y): """ This a funation add :param x: :param y: :return: """ return x + yprint("name={},\ndoc={}".format(add.__name__,add.__doc__))name=add,doc= This a funation add :param x: :param y: :return:
怎样才能使用,@logger装饰器的函数之后,显示add原函数的doc文档信息??
def logger(fn): def _loger(*args,**kwargs): "This funation logger" print("函数开始运行") ret = fn(*args,**kwargs) print("函数结束") return ret return _loger@loggerdef add(x,y): ''' This is funation add ''' return x + yprint(add.__name__,add.__doc__)结果:_loger This funation logger
变法一:自己编写函数去实现
- 通过copy_properties函数将被包装函数的属性覆盖掉包装函数
- 凡是被装饰的函数都需要复制这些属性,这个函数很通用
- 可以将复制属性的函数构建成装饰器函数,带参装饰器
def copy_doc(src,dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__def logger(fn): def loger(*args,**kwargs): "This funation logger" print("函数开始运行") ret = fn(*args,**kwargs) print("函数结束") return ret copy_doc(fn,loger) return loger@loggerdef add(x,y): ''' This is funation add ''' return x + yprint(add(3,6),add.__name__,add.__doc__)结果:函数开始运行函数结束9 add This is funation add
变法二:进一步改变为装饰器函数
def copy_doc(src): def _copy(dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ return dst return _copydef logger(fn): @copy_doc(fn) #copy_doc(fn,loger) def loger(*args,**kwargs): "This funation logger" print("函数开始运行") ret = fn(*args,**kwargs) print("函数结束") return ret return loger@loggerdef add(x,y): ''' This is funation add ''' return x + yprint(add(3,6),add.__name__,add.__doc__)结果:函数开始运行函数结束9 add This is funation add
带参装饰器
带参装饰器
- 函数作为它的形参
- 返回值是一个不带参的装饰器函数
- 使用@functionname(参数列表)方式调用
- 可以看做在装饰器外层又加了一层函数
例子:计算函数运行行多长时间
import datetimeimport timedef 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).total_seconds() print("function {} took {}s.".format(fn.__name__, duration)) return ret return wrap@logger # 相当于 add = logger(add)def add(x, y): print("===call add===========") time.sleep(2) return x + yprint(add(4, y=7))结果:args=(4,), kwargs={'y': 7}===call add===========function add took 2.007478s.11
上面的例子,不够灵活,如果我们计算,大于3秒,小于5秒的函数,改怎么来改
- 时间自己来控制
import datetimeimport timedef logger(t1,t2): def t_time(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 >t1 and duration < t2: print("function {} took {}s.".format(fn.__name__, duration)) return ret return wrap return t_time@logger(3,5) # 相当于 add = logger(add)def add(x, y): print("===call add===========") time.sleep(4) return x + yprint(add(4, y=7))结果:args=(4,), kwargs={'y': 7}===call add===========function add took 4.002905s.11
总结
最难的装饰器也就是上面个这个样子了
将记录的功能提取出来,这样就可以通过外部提供的函数来灵活的控制输出
import datetimedef copy_doc(src): def _copy(dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ return dst return _copydef logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))): def _logger(fn): @copy_doc(fn) # wrapper = wrapper(fn)(wrapper) 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
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2025年04月05日 02时27分13秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
MA、WMA、EMA、EXPMA区别及公式详述
2019-03-04
阿里云云解析DNS各种概念深度剖析
2019-03-04
(20200328已解决)从docker容器内复制文件到宿主机
2019-03-04
理解Docker ulimit参数
2019-03-04
Factor Exposure因子暴露
2019-03-04
将DataFrame作为邮件正文HTML发送 in Python
2019-03-04
理解Python系统下的时间格式
2019-03-04
《经济机器是怎样运行的》笔记(三)
2019-03-04
Python提升回测速度concurrnet.futures模块详解
2019-03-04
Python语言'类'概念再理解
2019-03-04
(2019.6.27)Anaconda清华镜像已恢复使用
2019-03-04
Robomongo使用教程:踩着前辈的路
2019-03-04
Python中Class类与def函数的区别
2019-03-04
OpenAI Gym简介及初级实例
2019-03-04
用Matplotlib和Gym优雅地呈现股票交易智体
2019-03-04
Github上量化交易相关项目汇总
2019-03-04
JS取出两个数组中的不同或相同元素
2019-03-04
Ubuntu 18.04 zip压缩文件及其文件 夹中的所以 内容
2019-03-04