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中几个常用的类方法
Apr 08 Python
python删除过期文件的方法
May 29 Python
Python实现对象转换为xml的方法示例
Jun 08 Python
python flask实现分页效果
Jun 27 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 Python
python自动化生成IOS的图标
Nov 13 Python
Python 把序列转换为元组的函数tuple方法
Jun 27 Python
python/Matplotlib绘制复变函数图像教程
Nov 21 Python
Python中文分词库jieba,pkusegwg性能准确度比较
Feb 11 Python
Python virtualenv虚拟环境实现过程解析
Apr 18 Python
python tkiner实现 一个小小的图片翻页功能的示例代码
Jun 24 Python
python实现会员管理系统
Mar 18 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
ThinkPHP写第一个模块应用
2012/02/20 PHP
浅析php数据类型转换
2014/01/09 PHP
Codeigniter+PHPExcel实现导出数据到Excel文件
2014/06/12 PHP
PHP查找与搜索数组元素方法总结
2015/06/12 PHP
使用PHP生成二维码的方法汇总
2015/07/22 PHP
PHP+MySQL存储数据常见中文乱码问题小结
2016/06/13 PHP
php头像上传预览实例代码
2017/05/02 PHP
PHP递归实现汉诺塔问题的方法示例
2017/11/25 PHP
免费空间广告万能消除代码
2006/09/04 Javascript
Prototype 学习 Prototype对象
2009/07/12 Javascript
extjs实现选择多表自定义查询功能 前台部分(ext源码)
2011/12/20 Javascript
javascript中的=等号个数问题两个跟三个有什么区别
2013/10/23 Javascript
JavaScript对象属性检查、增加、删除、访问操作实例
2015/07/08 Javascript
JavaScript正则表达式的分组匹配详解
2016/02/13 Javascript
js 输入框 正则表达式(菜鸟必看教程)
2017/02/19 Javascript
vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
2017/04/13 Javascript
jQuery实现广告条滚动效果
2017/08/22 jQuery
基于JavaScript表单脚本(详解)
2017/10/18 Javascript
python 生成不重复的随机数的代码
2011/05/15 Python
Python彩色化Linux的命令行终端界面的代码实例分享
2016/07/02 Python
python正则分析nginx的访问日志
2017/01/17 Python
python opencv实现切变换 不裁减图片
2018/07/26 Python
python的pytest框架之命令行参数详解(下)
2019/06/27 Python
使用批处理脚本自动生成并上传NuGet包(操作方法)
2019/11/19 Python
Python Sympy计算梯度、散度和旋度的实例
2019/12/06 Python
python 图像的离散傅立叶变换实例
2020/01/02 Python
PyTorch笔记之scatter()函数的使用
2020/02/12 Python
Python中remove漏删和索引越界问题的解决
2020/03/18 Python
基于Python实现简单学生管理系统
2020/07/24 Python
GWT都有什么特性
2016/12/02 面试题
公共事业管理本科生求职信
2013/10/07 职场文书
计算机专业优秀大学生自我总结
2014/01/21 职场文书
售后服务承诺书怎么写
2014/05/21 职场文书
党员民主评议自我评价
2014/10/20 职场文书
实习计划书范文
2015/01/16 职场文书
超越Nginx的Web服务器caddy优雅用法
2022/06/21 Servers