Python如何创建装饰器时保留函数元信息


Posted in Python onAugust 07, 2020

问题

你写了一个装饰器作用在某个函数上,但是这个函数的重要的元信息比如名字、文档字符串、注解和参数签名都丢失了。

解决方案

任何时候你定义装饰器的时候,都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数。例如:

import time
from functools import wraps
def timethis(func):
  '''
  Decorator that reports the execution time.
  '''
  @wraps(func)
  def wrapper(*args, **kwargs):
    start = time.time()
    result = func(*args, **kwargs)
    end = time.time()
    print(func.__name__, end-start)
    return result
  return wrapper

下面我们使用这个被包装后的函数并检查它的元信息:

>>> @timethis
... def countdown(n):
...   '''
...   Counts down
...   '''
...   while n > 0:
...     n -= 1
...
>>> countdown(100000)
countdown 0.008917808532714844
>>> countdown.__name__
'countdown'
>>> countdown.__doc__
'\n\tCounts down\n\t'
>>> countdown.__annotations__
{'n': <class 'int'>}
>>>

讨论

在编写装饰器的时候复制元信息是一个非常重要的部分。如果你忘记了使用 @wraps , 那么你会发现被装饰函数丢失了所有有用的信息。比如如果忽略 @wraps 后的效果是下面这样的:

>>> countdown.__name__
'wrapper'
>>> countdown.__doc__
>>> countdown.__annotations__
{}
>>>

@wraps 有一个重要特征是它能让你通过属性 __wrapped__ 直接访问被包装函数。例如:

>>> countdown.__wrapped__(100000)
>>>

__wrapped__ 属性还能让被装饰函数正确暴露底层的参数签名信息。例如:

>>> from inspect import signature
>>> print(signature(countdown))
(n:int)
>>>

一个很普遍的问题是怎样让装饰器去直接复制原始函数的参数签名信息, 如果想自己手动实现的话需要做大量的工作,最好就简单的使用 @wraps 装饰器。 通过底层的 __wrapped__ 属性访问到函数签名信息。

以上就是Python如何创建装饰器时保留函数元信息的详细内容,更多关于Python保留函数元信息的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python使用稀疏矩阵节省内存实例
Jun 27 Python
Python3.2中的字符串函数学习总结
Apr 23 Python
Python中用于转换字母为小写的lower()方法使用简介
May 19 Python
浅谈Python类里的__init__方法函数,Python类的构造函数
Dec 10 Python
Python爬虫实例_城市公交网络站点数据的爬取方法
Jan 10 Python
在cmd中运行.py文件: python的操作步骤
May 12 Python
Python多线程threading模块用法实例分析
May 22 Python
Django2 连接MySQL及model测试实例分析
Dec 10 Python
关于初始种子自动选取的区域生长实例(python+opencv)
Jan 16 Python
python中for in的用法详解
Apr 17 Python
python 画图 图例自由定义方式
Apr 17 Python
python中pivot()函数基础知识点
Jan 03 Python
python的launcher用法知识点总结
Aug 07 #Python
详解PyQt5中textBrowser显示print语句输出的简单方法
Aug 07 #Python
PyQt5的相对布局管理的实现
Aug 07 #Python
详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)
Aug 07 #Python
Python configparser模块封装及构造配置文件
Aug 07 #Python
Python logging模块进行封装实现原理解析
Aug 07 #Python
Python定时任务APScheduler安装及使用解析
Aug 07 #Python
You might like
玩家交还《星际争霸》原始码光盘 暴雪报以厚礼
2017/05/05 星际争霸
php下使用SimpleXML 处理XML 文件
2010/02/27 PHP
php短域名转换为实际域名函数
2011/01/17 PHP
php标签云的实现代码
2012/10/10 PHP
深入探讨:Nginx 502 Bad Gateway错误的解决方法
2013/06/03 PHP
zend framework框架中url大小写问题解决方法
2014/08/19 PHP
ThinkPHP V2.2说明文档没有说明的那些事实例小结
2015/07/01 PHP
PHP array_shift()用法实例分析
2019/01/07 PHP
JavaScript 中的事件教程
2007/04/05 Javascript
jQuery 菜单随滚条改为以定位方式(固定要浏览器顶部)
2012/05/24 Javascript
nodejs win7下安装方法
2012/05/24 NodeJs
js 异步操作回调函数如何控制执行顺序
2013/12/24 Javascript
JS在一定时间内跳转页面及各种刷新页面的实现方法
2016/05/26 Javascript
js实现方块上下左右移动效果
2017/08/17 Javascript
BootStrap下的弹出框加载select2框架失败的解决方法
2017/08/31 Javascript
值得收藏的八个常用的js正则表达式
2018/10/19 Javascript
JavaScript设计模式之代理模式实例分析
2019/01/16 Javascript
使用node搭建自动发图文微博机器人的方法
2019/03/22 Javascript
详解Js里的for…in和for…of的用法
2019/03/28 Javascript
selenium+python自动化测试之页面元素定位
2019/01/23 Python
Python列表常见操作详解(获取,增加,删除,修改,排序等)
2019/02/18 Python
python使用pygame实现笑脸乒乓球弹珠球游戏
2019/11/25 Python
使用tensorflow DataSet实现高效加载变长文本输入
2020/01/20 Python
Python命令行参数argv和argparse该如何使用
2021/02/08 Python
详解css3中的伪类before和after常见用法
2020/11/17 HTML / CSS
深入解析HTML5使用SVG图像时的viewBox属性用法
2015/09/02 HTML / CSS
计算机毕业大学生推荐信
2013/12/01 职场文书
优秀信贷员先进事迹
2014/01/31 职场文书
小学生开学感言
2014/02/28 职场文书
主办会计岗位职责
2014/03/13 职场文书
庆祝三八妇女节标语
2014/10/09 职场文书
2014年幼儿园教学工作总结
2014/12/04 职场文书
旅游项目合作意向书
2015/05/08 职场文书
2015年出纳工作总结与计划
2015/05/18 职场文书
python中Tkinter 窗口之输入框和文本框的实现
2021/04/12 Python
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers