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学习笔记 下载
Feb 10 Python
在Python中调用ggplot的三种方法
Apr 08 Python
python学习 流程控制语句详解
Jun 01 Python
Python实现的微信公众号群发图片与文本消息功能实例详解
Jun 30 Python
Python实现字符串与数组相互转换功能示例
Sep 22 Python
Django使用Celery异步任务队列的使用
Mar 13 Python
在Python中通过getattr获取对象引用的方法
Jan 21 Python
安装好Pycharm后如何配置Python解释器简易教程
Jun 28 Python
python执行scp命令拷贝文件及文件夹到远程主机的目录方法
Jul 08 Python
Python关于拓扑排序知识点讲解
Jan 04 Python
python利用后缀表达式实现计算器功能
Feb 22 Python
jupyter notebook保存文件默认路径更改方法汇总(亲测可以)
Jun 09 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
《星际争霸重制版》兵种对比图鉴
2020/03/02 星际争霸
239军机修复记
2021/03/02 无线电
php生成文件
2007/01/15 PHP
基于PHP后台的Android新闻浏览客户端
2016/05/23 PHP
PHP获取HTTP body内容的方法
2018/12/31 PHP
cnblogs TagCloud基于jquery的实现代码
2010/06/11 Javascript
jquery写个checkbox——类似邮箱全选功能
2013/03/19 Javascript
JS.findElementById()使用介绍
2013/09/21 Javascript
Javascript快速排序算法详解
2014/12/03 Javascript
javascript中数组的定义及使用实例
2015/01/21 Javascript
jquery实现图片切换代码
2016/10/13 Javascript
微信小程序 ecshop地址三级联动实现实例代码
2017/02/28 Javascript
js正则表达式验证密码强度【推荐】
2017/03/03 Javascript
JS中正则表达式全局匹配模式 /g用法详解
2017/04/01 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
2019/05/10 Javascript
改进 JavaScript 和 Rust 的互操作性并深入认识 wasm-bindgen 组件
2019/07/13 Javascript
JS实现手写 forEach算法示例
2020/04/29 Javascript
微信小程序点击滚动到指定位置的实现
2020/05/22 Javascript
[01:18]一目了然!DOTA2DotA快捷操作对比第一弹
2014/07/01 DOTA
[48:31]完美世界DOTA2联赛PWL S3 DLG vs Phoenix 第二场 12.17
2020/12/19 DOTA
[01:02:32]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD BO3 第二场 2月26日
2021/03/11 DOTA
在Python的Flask框架中验证注册用户的Email的方法
2015/09/02 Python
Python Django 简单分页的实现代码解析
2019/08/21 Python
手机使用python操作图片文件(pydroid3)过程详解
2019/09/25 Python
python3连接kafka模块pykafka生产者简单封装代码
2019/12/23 Python
Python Numpy中数据的常用保存与读取方法
2020/04/01 Python
前端面试必备之CSS3的新特性
2017/09/05 HTML / CSS
字中字效果的实现【html5实例】
2016/05/03 HTML / CSS
微信小程序canvas实现水平、垂直居中效果
2020/02/05 HTML / CSS
Rowdy Gentleman服装和配饰:美好时光
2019/09/24 全球购物
《穷人》教学反思
2014/04/08 职场文书
中学教师师德师风演讲稿
2014/08/22 职场文书
交通事故被告代理词
2015/05/23 职场文书
鸦片战争观后感
2015/06/09 职场文书
关于车尾的标语大全
2015/08/11 职场文书
浅谈Redis 中的过期删除策略和内存淘汰机制
2022/04/03 Redis