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字符串转换成浮点数函数分享
Jul 24 Python
Python制作爬虫抓取美女图
Jan 20 Python
浅谈Python的异常处理
Jun 19 Python
python使用xlrd和xlwt读写Excel文件的实例代码
Sep 05 Python
Python多线程编程之多线程加锁操作示例
Sep 06 Python
python保存二维数组到txt文件中的方法
Nov 15 Python
python 使用 requests 模块发送http请求 的方法
Dec 09 Python
python使用正则筛选信用卡
Jan 27 Python
python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
Apr 01 Python
Python3+Appium实现多台移动设备操作的方法
Jul 05 Python
图解python全局变量与局部变量相关知识
Nov 02 Python
Python测试框架pytest高阶用法全面详解
Jun 01 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实现的仿阿里巴巴实现同类产品翻页
2009/12/11 PHP
PHP验证码函数代码(简单实用)
2013/09/29 PHP
PHP正则提取不包含指定网址的图片地址的例子
2014/04/21 PHP
php按百分比生成缩略图的代码分享
2014/05/10 PHP
PHP中调用C/C++制作的动态链接库的教程
2016/03/10 PHP
php UNIX时间戳用法详解
2017/02/16 PHP
PHP排序算法之堆排序(Heap Sort)实例详解
2018/04/21 PHP
ExtJs的Date格式字符代码
2010/12/30 Javascript
别了 JavaScript中的isXX系列
2012/08/01 Javascript
jquery 插件学习(三)
2012/08/06 Javascript
Js点击弹出下拉菜单效果实例
2013/08/12 Javascript
一段非常简单的js判断浏览器的内核
2014/08/17 Javascript
jquery.multiselect多选下拉框实现代码
2016/11/11 Javascript
分分钟玩转Vue.js组件(二)
2017/03/01 Javascript
nodejs入门教程五:连接数据库的方法分析
2017/04/24 NodeJs
Express系列之multer上传的使用
2017/10/27 Javascript
JavaScript数组、json对象、eval()函数用法实例分析
2019/02/21 Javascript
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
element中Steps步骤条和Tabs标签页关联的解决
2020/12/08 Javascript
[04:22]DSPL第二期精彩集锦:残血反杀!
2014/12/10 DOTA
python通过smpt发送邮件的方法
2015/04/30 Python
python使用win32com库播放mp3文件的方法
2015/05/30 Python
Python使用dis模块把Python反编译为字节码的用法详解
2016/06/14 Python
numpy下的flatten()函数用法详解
2019/05/27 Python
在Pycharm中调试Django项目程序的操作方法
2019/07/17 Python
python实现梯度法 python最速下降法
2020/03/24 Python
使用Keras预训练好的模型进行目标类别预测详解
2020/06/27 Python
基于OpenCV的网络实时视频流传输的实现
2020/11/15 Python
关于Python 解决Python3.9 pandas.read_excel(‘xxx.xlsx‘)报错的问题
2020/11/28 Python
HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述
2013/01/30 HTML / CSS
详解HTML5 data-* 自定义属性
2018/01/24 HTML / CSS
SQL Server的固定数据库角色都有哪些?对应的服务器权限有哪些?
2013/05/18 面试题
会计电算化专业个人的自我评价
2013/11/24 职场文书
计划生育证明格式范本
2014/09/12 职场文书
教师听课学习心得体会
2016/01/15 职场文书
react中的DOM操作实现
2021/06/30 Javascript