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脚本来获取Google搜索结果的示例
May 04 Python
python计算圆周率pi的方法
Jul 11 Python
Python自定义线程类简单示例
Mar 23 Python
Python解析并读取PDF文件内容的方法
May 08 Python
通过python实现弹窗广告拦截过程详解
Jul 10 Python
pygame实现俄罗斯方块游戏(对战篇1)
Oct 29 Python
Python类反射机制使用实例解析
Dec 30 Python
python 非线性规划方式(scipy.optimize.minimize)
Feb 11 Python
Python实现多线程下载脚本的示例代码
Apr 03 Python
使用 Python 读取电子表格中的数据实例详解
Apr 17 Python
Keras之自定义损失(loss)函数用法说明
Jun 10 Python
Django drf请求模块源码解析
Jun 08 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
PHP foreach循环使用详解与实例代码
2010/05/08 PHP
php 编写安全的代码时容易犯的错误小结
2010/05/20 PHP
php字符串过滤strip_tags()函数用法实例分析
2019/06/24 PHP
javascript(jquery)利用函数修改全局变量的代码
2009/11/02 Javascript
Jquery作者John Resig自己封装的javascript 常用函数
2009/11/09 Javascript
JQuery 中几个类选择器的简单使用介绍
2013/03/14 Javascript
利用进制转换压缩数字函数分享
2014/01/02 Javascript
Vue.js每天必学之指令系统与自定义指令
2016/09/07 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
利用Chrome DevTools直接调试Node.js和JavaScript的方法详解(并行)
2017/02/16 Javascript
解决AngualrJS页面刷新导致异常显示问题
2017/04/20 Javascript
基于LayUI分页和LayUI laypage分页的使用示例
2017/08/02 Javascript
在vue-cli中组件通信的方法
2017/12/16 Javascript
微信小程序实现手势图案锁屏功能
2018/01/30 Javascript
electron实现静默打印的示例代码
2019/08/12 Javascript
js中关于Blob对象的介绍与使用
2019/11/29 Javascript
微信小程序聊天功能的示例代码
2020/01/13 Javascript
python通过自定义isnumber函数判断字符串是否为数字的方法
2015/04/23 Python
Python卸载模块的方法汇总
2016/06/07 Python
Python中文分词实现方法(安装pymmseg)
2016/06/14 Python
python清理子进程机制剖析
2017/11/23 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
解决Pytorch 加载训练好的模型 遇到的error问题
2020/01/10 Python
详解python破解zip文件密码的方法
2020/01/13 Python
Python如何获取文件指定行的内容
2020/05/27 Python
Opencv求取连通区域重心实例
2020/06/04 Python
基于CentOS搭建Python Django环境过程解析
2020/08/24 Python
Python3 用什么IDE开发工具比较好
2020/11/28 Python
Python中生成ndarray实例讲解
2021/02/22 Python
美国家具网站:Cymax
2016/09/17 全球购物
优秀毕业生事迹材料
2014/02/12 职场文书
高级销售求职信
2014/02/21 职场文书
小学生竞选班干部演讲稿(5篇)
2014/09/12 职场文书
家属联谊会致辞
2015/07/31 职场文书
2016年教师节慰问信
2015/12/01 职场文书
详细了解MVC+proxy
2021/07/09 Java/Android