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 相关文章推荐
python3.3使用tkinter开发猜数字游戏示例
Mar 14 Python
python使用心得之获得github代码库列表
Jun 25 Python
详解Python中的Descriptor描述符类
Jun 14 Python
Python3实现发送QQ邮件功能(附件)
Dec 23 Python
python实现外卖信息管理系统
Jan 11 Python
基于tensorflow加载部分层的方法
Jul 26 Python
CentOS7下python3.7.0安装教程
Jul 30 Python
Python logging模块用法示例
Aug 28 Python
Python进阶之使用selenium爬取淘宝商品信息功能示例
Sep 16 Python
Python Http请求json解析库用法解析
Nov 28 Python
两行代码解决Jupyter Notebook中文不能显示的问题
Apr 24 Python
Python如何把不同类型数据的json序列化
Apr 30 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
PHP中isset()和unset()函数的用法小结
2014/03/11 PHP
PHP后门隐藏的一些技巧总结
2020/11/04 PHP
javascript 单选框,多选框美化代码
2008/08/01 Javascript
innerHTML,outerHTML,innerText,outerText的用法及区别解析
2013/12/16 Javascript
用jquery实现动画跳到顶部和底部(这个比较简单)
2014/09/01 Javascript
js判断一个字符串是否包含一个子串的方法
2015/01/26 Javascript
jquery拖拽效果完整实例(附demo源码下载)
2016/01/14 Javascript
JS留言功能的简单实现案例(推荐)
2016/06/23 Javascript
Javascript中获取浏览器类型和操作系统版本等客户端信息常用代码
2016/06/28 Javascript
原生JavaScript制作计算器
2016/10/16 Javascript
jQuery实现三级联动效果
2017/03/02 Javascript
JavaScript数据结构之广义表的定义与表示方法详解
2017/04/12 Javascript
纯js实现动态时间显示
2020/09/07 Javascript
vue.js移动端tab组件的封装实践实例
2017/06/30 Javascript
js生成word中图片处理方法
2018/01/06 Javascript
element ui 表格动态列显示空白bug 修复方法
2018/09/04 Javascript
python持久性管理pickle模块详细介绍
2015/02/18 Python
使用pandas读取csv文件的指定列方法
2018/04/21 Python
python实现windows下文件备份脚本
2018/05/27 Python
详解pyenv下使用python matplotlib模块的问题解决
2018/11/29 Python
python3实现名片管理系统
2020/11/29 Python
对Python 语音识别框架详解
2018/12/24 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
详解python做UI界面的方法
2019/02/27 Python
PyQt4 treewidget 选择改变颜色,并设置可编辑的方法
2019/06/17 Python
python实现拉普拉斯特征图降维示例
2019/11/25 Python
python查看矩阵的行列号以及维数方式
2020/05/22 Python
python如何将图片转换素描画
2020/09/08 Python
python实现简单贪吃蛇游戏
2020/09/29 Python
美国最大的香水连锁店官网:Perfumania
2016/08/15 全球购物
临床医师专业个人自我评价
2014/01/08 职场文书
群众路线教育实践活动心得体会
2014/03/07 职场文书
学校运动会报道稿
2014/09/23 职场文书
小学生勤俭节约倡议书
2015/04/29 职场文书
如何使用 resize 实现图片切换预览功能
2021/08/23 HTML / CSS
解决Python保存文件名太长OSError: [Errno 36] File name too long
2022/05/11 Python