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的@property装饰器的用法
Apr 28 Python
教大家使用Python SqlAlchemy
Feb 12 Python
python导入csv文件出现SyntaxError问题分析
Dec 15 Python
python进阶之多线程对同一个全局变量的处理方法
Nov 09 Python
django query模块
Apr 20 Python
python如何制作英文字典
Jun 25 Python
在Pycharm中调试Django项目程序的操作方法
Jul 17 Python
解决Python使用列表副本的问题
Dec 19 Python
基于virtualenv创建python虚拟环境过程图解
Mar 30 Python
django 解决扩展自带User表遇到的问题
May 14 Python
Python 常用日期处理 -- calendar 与 dateutil 模块的使用
Sep 02 Python
使用opencv-python如何打开USB或者笔记本前置摄像头
Jun 21 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
Discuz! Passport 通行证整合
2008/03/27 PHP
ThinkPHP使用UTFWry地址库进行IP定位实例
2014/04/01 PHP
PHP的PDO大对象(LOBs)
2019/01/27 PHP
JQery jstree 大数据量问题解决方法
2010/03/09 Javascript
Jquery getJSON方法详细分析
2013/12/26 Javascript
JS获取地址栏参数的几种方法小结
2014/02/28 Javascript
一个可以增加和删除行的table并可编辑表格中内容
2014/06/16 Javascript
js中hash和ico的关联分析
2015/02/05 Javascript
JS判断元素是否在数组内的实现代码
2016/03/30 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
微信小程序使用第三方库Underscore.js步骤详解
2016/09/27 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
Javascript 制作图形验证码实例详解
2016/12/22 Javascript
利用Javascript实现简单的转盘抽奖
2017/02/13 Javascript
详解JavaScript对象的深浅复制
2017/03/30 Javascript
JS实现div模块的截图并下载功能
2017/10/17 Javascript
Vuex持久化插件(vuex-persistedstate)解决刷新数据消失的问题
2019/04/16 Javascript
微信小程序 调用微信授权窗口相关问题解决
2019/07/25 Javascript
es6 for循环中let和var区别详解
2020/01/12 Javascript
[42:22]DOTA2上海特级锦标赛C组小组赛#1 OG VS Archon第一局
2016/02/27 DOTA
Python编写百度贴吧的简单爬虫
2015/04/02 Python
tensorflow 获取模型所有参数总和数量的方法
2018/06/14 Python
Python3.6使用tesseract-ocr的正确方法
2018/10/17 Python
Python Tkinter Entry和Text的添加与使用详解
2020/03/04 Python
python 如何调用 dubbo 接口
2020/09/24 Python
豪华复古化妆:Besame Cosmetics
2019/09/06 全球购物
美国传奇滑手Paul Rodriguez创办的街头滑板品牌:Primitive Skateboarding
2019/10/29 全球购物
社会保险接收函
2014/01/12 职场文书
《雨点儿》教学反思
2014/04/14 职场文书
校园元旦活动总结
2014/07/09 职场文书
教师工作表现评语
2014/12/31 职场文书
员工规章制度范本
2015/08/07 职场文书
生产实习心得体会范文
2016/01/22 职场文书
详解分布式系统中如何用python实现Paxos
2021/05/18 Python
MySQL的prepare使用以及遇到的bug
2022/05/11 MySQL
windows server 2016 域环境搭建的方法步骤(图文)
2022/06/25 Servers