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中为feedparser设置超时时间避免堵塞
Sep 28 Python
Python实现购物程序思路及代码
Jul 24 Python
Python装饰器的执行过程实例分析
Jun 04 Python
解决python os.mkdir创建目录失败的问题
Oct 16 Python
利用python实现在微信群刷屏的方法
Feb 21 Python
python线程中的同步问题及解决方法
Aug 29 Python
python采集百度搜索结果带有特定URL的链接代码实例
Aug 30 Python
Pytorch 使用 nii数据做输入数据的操作
May 26 Python
Python API 操作Hadoop hdfs详解
Jun 06 Python
通过代码实例解析Pytest运行流程
Aug 20 Python
python 装饰器的实际作用有哪些
Sep 07 Python
OpenCV-Python实现轮廓拟合
Jun 08 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 minixml详解
2008/07/19 PHP
一些使用频率比较高的php函数
2008/10/03 PHP
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
PHP基于迭代实现文件夹复制、删除、查看大小等操作的方法
2017/08/11 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
PHP实现一个轻量级容器的方法
2019/01/28 PHP
javascript编程起步(第六课)
2007/01/10 Javascript
JS控件的生命周期介绍
2012/10/22 Javascript
图片上传判断及预览脚本的效果实例
2013/08/07 Javascript
javascript的内存管理详解
2013/08/07 Javascript
基于Jquery实现键盘按键监听
2014/05/11 Javascript
jquery动态改变form属性提交表单
2014/06/03 Javascript
JavaScript闭包实例详解
2016/06/03 Javascript
jQuery中常用动画效果函数(日常整理)
2016/09/17 Javascript
深入了解JavaScript的逻辑运算符(与、或)
2016/12/20 Javascript
jQuery实现视频展示效果
2020/05/30 jQuery
2020京东618叠蛋糕js脚本(亲测好用)
2020/06/02 Javascript
vue使用keep-alive实现组件切换时保存原组件数据方法
2020/10/30 Javascript
[44:50]DOTA2上海特级锦标赛B组小组赛#2 VG VS Fnatic第二局
2016/02/26 DOTA
基于Python Shell获取hostname和fqdn释疑
2016/01/25 Python
Django unittest 设置跳过某些case的方法
2018/12/26 Python
python集合是否可变总结
2019/06/20 Python
通过字符串导入 Python 模块的方法详解
2019/10/27 Python
浅谈ROC曲线的最佳阈值如何选取
2020/02/28 Python
Python hashlib和hmac模块使用方法解析
2020/12/08 Python
香蕉共和国工厂店:Banana Republic Factory
2018/06/09 全球购物
儿科护士实习自我鉴定
2013/10/17 职场文书
大学自我鉴定
2013/12/20 职场文书
《冬阳童年骆驼队》教学反思
2014/04/15 职场文书
学校节能减排方案
2014/06/13 职场文书
三分钟自我介绍演讲稿
2014/08/21 职场文书
创先争优活动心得体会
2014/09/04 职场文书
2014年采购员工作总结
2014/11/18 职场文书
2015公务员试用期工作总结
2014/12/12 职场文书
教师工作表现评语
2014/12/31 职场文书
golang interface判断为空nil的实现代码
2021/04/24 Golang