Python装饰器原理与简单用法实例分析


Posted in Python onApril 29, 2018

本文实例讲述了Python装饰器原理与简单用法。分享给大家供大家参考,具体如下:

今天整理装饰器,内嵌的装饰器、让装饰器带参数等多种形式,非常复杂,让人头疼不已。但是突然间发现了装饰器的奥秘,原来如此简单。。。。

第一步 :从最简单的例子开始

# -*- coding:gbk -*-
'''示例1: 使用语法糖@来装饰函数,相当于"myfunc = deco(myfunc)"
但发现新函数只在第一次被调用,且原函数多调用了一次'''
def deco(func):
  print("before myfunc() called.")
  func()
  print(" after myfunc() called.")
  return func
@deco
def myfunc():
  print(" myfunc() called.")
myfunc()
myfunc()

这是一个最简单的装饰器的例子,但是这里有一个问题,就是当我们两次调用myfunc()的时候,发现装饰器函数只被调用了一次。为什么会这样呢?要解释这个就要给出破解装饰器的关键钥匙了。

这里@deco这一句,和myfunc = deco(myfunc)其实是完全等价的,只不过是换了一种写法而已

一定要记住上面这句!!!!

好了,从现在开始,只需要做替换操作就可以了。

将@deco 替换为 myfunc = deco(myfunc)

程序首先调用deco(myfunc),得到的返回结果赋值给了myfunc (注意:在Python中函数名只是个指向函数首地址的函数指针而已)

deco(myfunc)的返回值就是函数myfunc()的地址

这样其实myfunc 没有变化,也就是说,最后的两次myfunc()函数调用,其实都没有执行到deco()

有同学就问了,明明打印了deco()函数里面的内容啊,怎么说没有调用到呢。这位同学一看就是没有注意听讲,那一次打印是在@deco 这一句被执行的。大家亲自动手试一下就会发现" myfunc() called." 这句打印输出了三次。多的那次就是@deco这里输出的,因为@deco 等价于myfunc = deco(myfunc),这里已经调用了deco()函数了。

第二步 :确保装饰器被调用

怎么解决装饰器没有被调用的问题呢

# -*- coding:gbk -*-
'''示例2: 使用内嵌包装函数来确保每次新函数都被调用,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
  def _deco():
    print("before myfunc() called.")
    func()
    print(" after myfunc() called.")
    # 不需要返回func,实际上应返回原函数的返回值
  return _deco
@deco
def myfunc():
  print(" myfunc() called.")
  return 'ok'
myfunc()
myfunc()

这里其实不需要我解释了,还是按照第一步中的方法做替换就可以了。还是??录妇浒伞!?/p>

@deco 替换为 myfunc = deco(myfunc)

程序首先调用deco(myfunc),得到的返回结果赋值给了myfunc ,这样myfunc 就变成了指向函数_deco()的指针

以后的myfunc(),其实是调用_deco()

第三步 :对带参数的函数进行装饰

破案过程和第一步、第二步完全一致,不再重复了

# -*- coding:gbk -*-
'''示例5: 对带参数的函数进行装饰,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
  def _deco(a, b):
    print("before myfunc() called.")
    ret = func(a, b)
    print(" after myfunc() called. result: %s" % ret)
    return ret
  return _deco
@deco
def myfunc(a, b):
  print(" myfunc(%s,%s) called." % (a, b))
  return a + b
myfunc(1, 2)
myfunc(3, 4)

第四步 :让装饰器带参数

# -*- coding:gbk -*-
'''示例7: 在示例4的基础上,让装饰器带参数,
和上一示例相比在外层多了一层包装。
装饰函数名实际上应更有意义些'''
def deco(arg):
  def _deco(func):
    def __deco():
      print("before %s called [%s]." % (func.__name__, arg))
      func()
      print(" after %s called [%s]." % (func.__name__, arg))
    return __deco
  return _deco
@deco("mymodule")
def myfunc():
  print(" myfunc() called.")
@deco("module2")
def myfunc2():
  print(" myfunc2() called.")
myfunc()
myfunc2()

这种带参数的装饰器怎么解释呢。其实是一样的,还是我们的替换操作

@deco("mymodule")替换为myfunc = deco("mymodule")(myfunc )

注意啊,这里deco后面跟了两个括号。

有同学要问了,这是什么意思?

其实很简单,先执行deco("mymodule"),返回结果为_deco

再执行_deco(myfunc),得到的返回结果为__deco

所以myfunc = __deco

破案!

更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
详解Python中for循环的使用
Apr 14 Python
Python常用内置模块之xml模块(详解)
May 23 Python
Scrapy爬虫实例讲解_校花网
Oct 23 Python
详解Python使用tensorflow入门指南
Feb 09 Python
Python cookbook(数据结构与算法)从字典中提取子集的方法示例
Mar 22 Python
Pyspider中给爬虫伪造随机请求头的实例
May 07 Python
python Kmeans算法原理深入解析
Aug 23 Python
Python类如何定义私有变量
Feb 03 Python
tensorflow 报错unitialized value的解决方法
Feb 06 Python
python中数字是否为可变类型
Jul 08 Python
Python迭代器协议及for循环工作机制详解
Jul 14 Python
python数字图像处理之图像的批量处理
Jun 28 Python
Python2.7 实现引入自己写的类方法
Apr 29 #Python
Python 实现引用其他.py文件中的类和类的方法
Apr 29 #Python
python 读取txt中每行数据,并且保存到excel中的实例
Apr 29 #Python
python实现读Excel写入.txt的方法
Apr 29 #Python
python Pandas 读取txt表格的实例
Apr 29 #Python
在python win系统下 打开TXT文件的实例
Apr 29 #Python
用Python写脚本,实现完全备份和增量备份的示例
Apr 29 #Python
You might like
tp5(thinkPHP5)操作mongoDB数据库的方法
2018/01/20 PHP
PHP实现一个限制实例化次数的类示例
2019/09/16 PHP
论坛里点击别人帖子下面的回复,回复标题变成“回复 24# 的帖子”
2009/06/14 Javascript
jQuery.Autocomplete实现自动完成功能(详解)
2010/07/13 Javascript
浅谈javascript的原型继承
2012/07/25 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
解析jQuery的三种bind/One/Live事件绑定使用方法
2013/12/30 Javascript
JavaScript怎么判断图片是否加载完成以便获取其尺寸
2014/05/08 Javascript
jquery网页回到顶部效果(图标渐隐,自写)
2014/06/16 Javascript
javascript定时器完整实例
2015/02/10 Javascript
javascript实现博客园页面右下角返回顶部按钮
2015/02/22 Javascript
jQuery获取checkboxlist的value值的方法
2015/09/27 Javascript
JS实现放大、缩小及拖拽图片的方法【可兼容IE、火狐】
2016/08/23 Javascript
Angularjs 双向绑定时字符串的转换成数字类型的问题
2017/06/12 Javascript
vue.js学习之UI组件开发教程
2017/07/03 Javascript
Vue press 支持图片放大功能的实例代码
2018/11/09 Javascript
Node.js开发之套接字(socket)编程入门示例
2019/11/05 Javascript
JS插入排序简单理解与实现方法分析
2019/11/25 Javascript
vue页面更新patch的实现示例
2020/03/25 Javascript
解决vue+webpack项目接口跨域出现的问题
2020/08/10 Javascript
[50:05]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
浅谈Python基础之I/O模型
2017/05/11 Python
Python实现PS滤镜的万花筒效果示例
2018/01/23 Python
Python3几个常见问题的处理方法
2019/02/26 Python
python飞机大战pygame游戏背景设计详解
2019/12/17 Python
快速创建python 虚拟环境
2020/11/28 Python
pycharm 快速解决python代码冲突的问题
2021/01/15 Python
前端面试必备之html5的新特性
2017/09/05 HTML / CSS
中国旅游网站:途牛旅游网
2019/09/29 全球购物
Nike墨西哥官网:Nike MX
2020/08/30 全球购物
装饰活动策划方案
2014/02/11 职场文书
小学生开学第一课活动方案
2014/03/27 职场文书
酒店管理专业毕业生求职自荐信
2014/04/28 职场文书
2015年度销售个人工作总结
2015/03/31 职场文书
2015年学习部工作总结范文
2015/03/31 职场文书
研讨会致辞
2015/07/31 职场文书