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 从远程服务器下载日志文件的程序
Feb 10 Python
python使用wxPython打开并播放wav文件的方法
Apr 24 Python
int在python中的含义以及用法
Jun 27 Python
python如何实现代码检查
Jun 28 Python
python打包exe开机自动启动的实例(windows)
Jun 28 Python
python单例模式的多种实现方法
Jul 26 Python
PyQt5中QTableWidget如何弹出菜单的示例代码
Feb 23 Python
django rest framework 过滤时间操作
Jul 12 Python
python实现大文本文件分割成多个小文件
Apr 20 Python
Python 解决空列表.append() 输出为None的问题
May 23 Python
Python快速实现一键抠图功能的全过程
Jun 29 Python
在NumPy中深拷贝和浅拷贝相关操作的定义和背后的原理
Apr 14 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 URL跳转代码 减少外链
2011/06/25 PHP
Android ProgressBar进度条和ProgressDialog进度框的展示DEMO
2013/06/19 PHP
解析php中curl_multi的应用
2013/07/17 PHP
PHP函数eval()介绍和使用示例
2014/08/20 PHP
php获取ajax的headers方法与内容实例
2017/12/27 PHP
PHP获取链表中倒数第K个节点的方法
2018/01/18 PHP
Django 标签筛选的实现代码(一对多、多对多)
2018/09/05 PHP
javascript中onclick(this)用法介绍
2013/04/19 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
jQuery制作圣诞主题页面 更像是爱情影集
2016/08/10 Javascript
微信小程序购物商城系统开发系列-目录结构介绍
2016/11/21 Javascript
Bootstrap表单制作代码
2017/03/17 Javascript
利用js编写网页进度条效果
2017/10/08 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
webpack打包html里面img后src为“[object Module]”问题
2019/12/22 Javascript
JavaScript实现打砖块游戏
2020/02/25 Javascript
Vue CLI4 Vue.config.js标准配置(最全注释)
2020/06/05 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
2020/08/31 Javascript
Python实现压缩和解压缩ZIP文件的方法分析
2017/09/28 Python
Python异常处理操作实例详解
2018/05/10 Python
python pands实现execl转csv 并修改csv指定列的方法
2018/12/12 Python
python实现flappy bird游戏
2018/12/24 Python
Python将string转换到float的实例方法
2019/07/29 Python
Python Matplotlib简易教程(小白教程)
2020/07/28 Python
Python实现EM算法实例代码
2020/10/04 Python
关于canvas绘制模糊问题的解决方法
2019/09/24 HTML / CSS
罗技美国官网:Logitech美国
2020/01/22 全球购物
写给妈妈的道歉信
2014/01/11 职场文书
澳大利亚商务邀请函
2014/01/17 职场文书
特色冷饮店创业计划书
2014/01/28 职场文书
酒店营销策划方案
2014/02/07 职场文书
美容院合作经营协议书
2014/10/10 职场文书
绍兴鲁迅故居导游词
2015/02/09 职场文书
MySQL开启事务的方式
2021/06/26 MySQL