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中的yield浅析
Jun 16 Python
Python中Django框架下的staticfiles使用简介
May 30 Python
python通过pip更新所有已安装的包实现方法
May 19 Python
Python中pygal绘制雷达图代码分享
Dec 07 Python
python读取文件名并改名字的实例
Jan 07 Python
python面向对象实现名片管理系统文件版
Apr 26 Python
django的auth认证,authenticate和装饰器功能详解
Jul 25 Python
python实现批量文件重命名
Oct 31 Python
python tkinter控件布局项目实例
Nov 04 Python
pytorch中的transforms模块实例详解
Dec 31 Python
Python文件操作基础流程解析
Mar 19 Python
python中的getter与setter你了解吗
Mar 24 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
全国FM电台频率大全 - 12 安徽省
2020/03/11 无线电
php 随机记录mysql rand()造成CPU 100%的解决办法
2010/05/18 PHP
解析PHP处理换行符的问题 \r\n
2013/06/13 PHP
php的数组与字符串的转换函数整理汇总
2013/07/18 PHP
PHP命令行脚本接收传入参数的三种方式
2014/08/20 PHP
PHP文件读写操作相关函数总结
2014/11/18 PHP
js玩一玩WSH吧
2007/02/23 Javascript
判断是否安装flash player及当前版本的JS代码
2013/08/08 Javascript
在子窗口中关闭父窗口的一句代码
2013/10/21 Javascript
js日期、星座的级联显示代码
2014/01/23 Javascript
一个通过script自定义属性传递配置参数的方法
2014/09/15 Javascript
JavaScript操作class和style样式代码详解
2016/02/13 Javascript
浅谈JS之iframe中的窗口
2016/09/13 Javascript
浅谈KOA2 Restful方式路由初探
2019/03/14 Javascript
vue  elementUI 表单嵌套验证的实例代码
2019/11/06 Javascript
vue实现短信验证码登录功能(流程详解)
2019/12/10 Javascript
如何使用webpack打包一个库library的方法步骤
2019/12/18 Javascript
vue实现前端分页完整代码
2020/06/17 Javascript
uniapp与webview之间的相互传值的实现
2020/06/29 Javascript
linux系统使用python监控apache服务器进程脚本分享
2014/01/15 Python
python通过文件头判断文件类型
2015/10/30 Python
基于python实现的抓取腾讯视频所有电影的爬虫
2016/04/22 Python
Python实现去除图片中指定颜色的像素功能示例
2019/04/13 Python
Django之使用celery和NGINX生成静态页面实现性能优化
2019/10/08 Python
Python3 mmap内存映射文件示例解析
2020/03/23 Python
Python3 pywin32模块安装的详细步骤
2020/05/26 Python
Python3利用scapy局域网实现自动多线程arp扫描功能
2021/01/21 Python
对象的序列化(serialization)类是面向流的,应如何将对象写入到随机存取文件中
2015/06/22 面试题
网络教育自我鉴定
2013/11/01 职场文书
出纳岗位职责模板
2013/11/27 职场文书
2014年关于两会精神的心得体会
2014/03/17 职场文书
静心口服夜广告词
2014/03/20 职场文书
2014年挂职干部工作总结
2014/12/06 职场文书
2014年个人技术工作总结
2014/12/08 职场文书
2016年“5.12”护士节致辞
2015/07/31 职场文书
Python 全局空间和局部空间
2022/04/06 Python