Python 在函数上添加包装器


Posted in Python onJuly 28, 2020

问题

你想在函数上添加一个包装器,增加额外的操作处理(比如日志、计时等)。

解决方案

如果你想使用额外的代码包装一个函数,可以定义一个装饰器函数,例如:

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(10000000)
countdown 0.87188299392912
>>>

讨论

一个装饰器就是一个函数,它接受一个函数作为参数并返回一个新的函数。当你像下面这样写:

@timethis
def countdown(n):
  pass

跟像下面这样写其实效果是一样的:

def countdown(n):
  pass
countdown = timethis(countdown)

顺便说一下,内置的装饰器比如 @staticmethod, @classmethod,@property 原理也是一样的。例如,下面这两个代码片段是等价的:

class A:
  @classmethod
  def method(cls):
    pass

class B:
  # Equivalent definition of a class method
  def method(cls):
    pass
  method = classmethod(method)

在上面的 wrapper() 函数中,装饰器内部定义了一个使用 *args 和 **kwargs 来接受任意参数的函数。在这个函数里面调用了原始函数并将其结果返回,不过你还可以添加其他额外的代码(比如计时)。然后这个新的函数包装器被作为结果返回来代替原始函数。

需要强调的是装饰器并不会修改原始函数的参数签名以及返回值。使用 *args 和 **kwargs 目的就是确保任何参数都能适用。而返回结果值基本都是调用原始函数 func(*args, **kwargs) 的返回结果,其中func就是原始函数。

刚开始学习装饰器的时候,会使用一些简单的例子来说明,比如上面演示的这个。不过实际场景使用时,还是有一些细节问题要注意的。比如上面使用 @wraps(func) 注解是很重要的,它能保留原始函数的元数据(下一小节会讲到),新手经常会忽略这个细节。接下来的几个小节我们会更加深入的讲解装饰器函数的细节问题,如果你想构造你自己的装饰器函数,需要认真看一下。

以上就是Python 在函数上添加包装器的详细内容,更多关于Python 添加包装器的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python中mechanize库的简单使用示例
Jan 10 Python
Python数据结构之Array用法实例
Oct 09 Python
django批量导入xml数据
Oct 16 Python
使用Python对Excel进行读写操作
Mar 30 Python
Python3利用SMTP协议发送E-mail电子邮件的方法
Sep 30 Python
Python numpy 常用函数总结
Dec 07 Python
python实现kMeans算法
Dec 21 Python
pandas.DataFrame 根据条件新建列并赋值的方法
Apr 08 Python
python防止随意修改类属性的实现方法
Aug 21 Python
python 实现将Numpy数组保存为图像
Jan 09 Python
pycharm激活方法到2099年(激活流程)
Sep 22 Python
python opencv角点检测连线功能的实现代码
Nov 24 Python
Python matplotlib图例放在外侧保存时显示不完整问题解决
Jul 28 #Python
Python 如何反方向迭代一个序列
Jul 28 #Python
Python Matplotlib简易教程(小白教程)
Jul 28 #Python
Python把图片转化为pdf代码实例
Jul 28 #Python
关于python3.7安装matplotlib始终无法成功的问题的解决
Jul 28 #Python
Python 合并拼接字符串的方法
Jul 28 #Python
Python reques接口测试框架实现代码
Jul 28 #Python
You might like
PHP 可阅读随机字符串代码
2010/05/26 PHP
教你如何使用php session
2013/10/28 PHP
PHP中遇到BOM、编码导致json_decode函数无法解析问题
2014/07/02 PHP
PHP对象的浅复制与深复制的实例详解
2017/10/26 PHP
JavaScript语言中的Literal Syntax特性分析
2007/03/08 Javascript
[原创]js与自动伸缩图片 自动缩小图片的多浏览器兼容的方法总结
2007/03/12 Javascript
JavaScript插入动态样式实现代码
2012/02/22 Javascript
JQuery下拉框应用示例介绍
2014/04/23 Javascript
iScroll中事件点击触发两次解决方案
2015/03/11 Javascript
有关JavaScript中call()和apply() 的一些理解
2016/05/20 Javascript
js以分隔符分隔数组中的元素并转换为字符串的方法
2016/11/16 Javascript
jQuery基本筛选选择器实例代码
2017/02/06 Javascript
基于js粘贴事件paste简单解析以及遇到的坑
2017/09/07 Javascript
Vue.js组件通信的几种姿势
2017/10/23 Javascript
纯js实现隔行变色效果
2017/11/29 Javascript
vue2.0学习之axios的封装与vuex介绍
2018/05/28 Javascript
vue使用ElementUI时导航栏默认展开功能的实现
2018/07/04 Javascript
利用chrome浏览器进行js调试并找出元素绑定的点击事件详解
2021/01/30 Javascript
新年快乐! javascript实现超级炫酷的3D烟花特效
2019/01/30 Javascript
详解Vue中Axios封装API接口的思路及方法
2020/10/10 Javascript
解决vant中 tab栏遇到的坑 van-tabs
2020/11/04 Javascript
[01:05:59]Mineski vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.22
2019/09/05 DOTA
[02:58]魔廷新尊——痛苦女王至宝语音台词节选
2020/06/14 DOTA
Python机器学习库scikit-learn安装与基本使用教程
2018/06/25 Python
Python加载数据的5种不同方式(收藏)
2020/11/13 Python
大韩航空官方网站:Korean Air
2017/10/25 全球购物
英国在线自行车店:Merlin Cycles
2018/08/20 全球购物
美国最好的钓鱼、狩猎和划船装备商店:Bass Pro Shops
2018/12/02 全球购物
简述安装Slackware Linux系统的过程
2012/05/08 面试题
试用期转正鉴定评语
2014/01/27 职场文书
目标管理责任书
2014/04/15 职场文书
学校节能宣传周活动总结
2014/07/09 职场文书
中职毕业生自我鉴定范文(3篇)
2014/09/28 职场文书
酒店人事主管岗位职责
2015/04/11 职场文书
Python机器学习之KNN近邻算法
2021/05/14 Python
Java集成swagger文档组件
2021/06/28 Java/Android