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 30 Python
Python实现简单的代理服务器
Jul 25 Python
Django视图之ORM数据库查询操作API的实例
Oct 27 Python
详解Python开发中如何使用Hook技巧
Nov 01 Python
python3实现名片管理系统
Nov 29 Python
django 外键model的互相读取方法
Dec 15 Python
Django web框架使用url path name详解
Apr 29 Python
翻转数列python实现,求前n项和,并能输出整个数列的案例
May 03 Python
python爬虫爬取淘宝商品比价(附淘宝反爬虫机制解决小办法)
Dec 03 Python
Django如何与Ajax交互
Apr 29 Python
实例讲解Python中sys.argv[]的用法
Jun 03 Python
python实现MD5进行文件去重的示例代码
Jul 09 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
关于shopex同步ucenter的redirect问题,导致script不运行
2013/04/10 PHP
禁止直接访问php文件代码分享
2020/05/05 PHP
修改jQuery Validation里默认的验证方法
2012/02/14 Javascript
jQuery回车实现登录简单实现
2013/08/20 Javascript
JQuery实现展开关闭层的方法
2015/02/17 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
基于jQuery实现页面搜索功能
2020/03/26 Javascript
BooStrap对导航条的改造实践小结
2016/09/21 Javascript
vue2.0构建单页应用最佳实战
2017/04/01 Javascript
微信小程序 slider的简单实例
2017/04/19 Javascript
xmlplus组件设计系列之文本框(TextBox)(3)
2017/05/03 Javascript
原生JS实现不断变化的标签
2017/05/22 Javascript
详解node nvm进行node多版本管理
2017/10/21 Javascript
layui 优化button按钮和弹出框的方法
2018/08/15 Javascript
使用Vue实现移动端左滑删除效果附源码
2019/05/16 Javascript
从0搭建vue-cli4脚手架
2020/06/17 Javascript
如何实现echarts markline标签名显示自己想要的
2020/07/20 Javascript
[02:57]2014DOTA2国际邀请赛 选手辛苦解说更辛苦
2014/07/10 DOTA
[02:57]DOTA2亚洲邀请赛小组赛第四日 赛事回顾
2015/02/02 DOTA
详细解析Python当中的数据类型和变量
2015/04/25 Python
python学习笔记之调用eval函数出现invalid syntax错误问题
2015/10/18 Python
CentOS7.3编译安装Python3.6.2的方法
2018/01/22 Python
Python Grid使用和布局详解
2018/06/30 Python
selenium+python 对输入框的输入处理方法
2018/10/11 Python
python 实现在tkinter中动态显示label图片的方法
2019/06/13 Python
python基于socket实现的UDP及TCP通讯功能示例
2019/11/01 Python
tf.concat中axis的含义与使用详解
2020/02/07 Python
移动端Web页面的CSS3 flex布局快速上手指南
2016/05/31 HTML / CSS
使用HTML5中的contentEditable来将多行文本自动增高
2016/03/01 HTML / CSS
HTML5+CSS设置浮动却没有动反而在中间且错行的问题
2020/05/26 HTML / CSS
医院保洁服务方案
2014/06/11 职场文书
纪检干部对照检查材料
2014/08/22 职场文书
教师党员批评与自我批评
2014/10/15 职场文书
防汛工作情况汇报
2014/10/28 职场文书
华山导游词
2015/02/03 职场文书
上课迟到检讨书范文
2015/05/06 职场文书