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网络编程学习笔记(五):socket的一些补充
Jun 09 Python
在Python程序和Flask框架中使用SQLAlchemy的教程
Jun 06 Python
python使用xpath中遇到:到底是什么?
Jan 04 Python
Python批量修改图片分辨率的实例代码
Jul 04 Python
python栈的基本定义与使用方法示例【初始化、赋值、入栈、出栈等】
Oct 24 Python
Python 依赖库太多了该如何管理
Nov 08 Python
配置python的编程环境之Anaconda + VSCode的教程
Mar 29 Python
解决Python 函数声明先后顺序出现的问题
Sep 02 Python
详解python命令提示符窗口下如何运行python脚本
Sep 11 Python
python文件路径操作方法总结
Dec 21 Python
详解用selenium来下载小姐姐图片并保存
Jan 26 Python
pytorch实现加载保存查看checkpoint文件
Jul 15 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限制文件下载速度的代码
2015/10/20 PHP
php基于PDO实现功能强大的MYSQL封装类实例
2017/02/27 PHP
jQuery学习4 浏览器的事件模型
2010/02/07 Javascript
JS实现div居中示例
2014/04/17 Javascript
js图片轮播特效代码分享
2015/09/07 Javascript
jQuery UI制作选项卡(tabs)
2016/12/13 Javascript
JavaScript实现区块链
2018/03/14 Javascript
javascript、php关键字搜索函数的使用方法
2018/05/29 Javascript
小程序实现抽奖动画
2020/04/16 Javascript
详解mpvue中使用vant时需要注意的onChange事件的坑
2019/05/16 Javascript
elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo
2019/07/03 Javascript
python中from module import * 的一个坑
2014/07/20 Python
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
2015/04/16 Python
分享python数据统计的一些小技巧
2016/07/21 Python
Python基于回溯法子集树模板实现图的遍历功能示例
2017/09/05 Python
使用 Python 实现微信群友统计器的思路详解
2018/09/26 Python
python学习之hook钩子的原理和使用
2018/10/25 Python
Python numpy.array()生成相同元素数组的示例
2018/11/12 Python
对python中类的继承与方法重写介绍
2019/01/20 Python
Python如何在循环内使用list.remove()
2020/06/01 Python
Keras 中Leaky ReLU等高级激活函数的用法
2020/07/05 Python
详解H5本地储存Web Storage
2017/07/03 HTML / CSS
使用Html5多媒体实现微信语音功能
2019/07/26 HTML / CSS
德国大型箱包和皮具商店:Koffer
2019/10/01 全球购物
学期自我鉴定范文
2013/10/01 职场文书
高中毕业生个人自我鉴定
2013/11/24 职场文书
求职简历推荐信范文
2013/12/02 职场文书
募捐倡议书
2014/04/14 职场文书
村党支部公开承诺书
2014/05/29 职场文书
2016年元旦主持词
2015/07/06 职场文书
军训后的感想
2015/08/07 职场文书
2016教师节问候语
2015/11/10 职场文书
Python爬虫基础讲解之请求
2021/05/13 Python
Python实现学生管理系统(面向对象版)
2021/06/24 Python
Python 的演示平台支持 WSGI 接口的应用
2022/04/20 Python
Python自动化实战之接口请求的实现
2022/05/30 Python