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字符串详细介绍
May 09 Python
Python实现给文件添加内容及得到文件信息的方法
May 28 Python
python使用arcpy.mapping模块批量出图
Mar 06 Python
Python WXPY实现微信监控报警功能的代码
Oct 20 Python
Python3实现的字典、列表和json对象互转功能示例
May 22 Python
使用Python读取二进制文件的实例讲解
Jul 09 Python
Python爬虫实现抓取京东店铺信息及下载图片功能示例
Aug 07 Python
Django跨域请求CSRF的方法示例
Nov 11 Python
自学python的建议和周期预算
Jan 30 Python
python实现的登录与提交表单数据功能示例
Sep 25 Python
win7上tensorflow2.2.0安装成功 引用DLL load failed时找不到指定模块 tensorflow has no attribute xxx 解决方法
May 20 Python
用python给csv里的数据排序的具体代码
Jul 17 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实现的任意进制互转类分享
2015/07/07 PHP
php对微信支付回调处理的方法
2018/08/23 PHP
javascript Xml增删改查(IE下)操作实现代码
2009/01/30 Javascript
JavaScript 对任意元素,自定义右键菜单的实现方法
2013/05/08 Javascript
移动端JQ插件hammer使用详解
2015/07/03 Javascript
跟我学习javascript的浮点数精度
2015/11/16 Javascript
javascript显示倒计时控制按钮的简单实现
2016/06/07 Javascript
深入浅出ES6之let和const命令
2016/08/25 Javascript
JS+HTML5实现的前端购物车功能插件实例【附demo源码下载】
2016/10/17 Javascript
jquery插件treegrid树状表格的使用方法详解(.Net平台)
2017/01/03 Javascript
Vue 2.0 服务端渲染入门介绍
2017/03/29 Javascript
angular学习之从零搭建一个angular4.0项目
2017/07/10 Javascript
js通过Date对象实现倒计时动画效果
2017/10/27 Javascript
setTimeout时间设置为0详细解析
2018/03/13 Javascript
react redux入门示例
2018/04/19 Javascript
vue采用EventBus实现跨组件通信及注意事项小结
2018/06/14 Javascript
从零开始搭建vue移动端项目到上线的步骤
2018/10/15 Javascript
详解关于element el-button使用$attrs的一个注意要点
2018/11/09 Javascript
小程序实现搜索框
2020/06/19 Javascript
Vue的Eslint配置文件eslintrc.js说明与规则介绍
2020/02/03 Javascript
python利用beautifulSoup实现爬虫
2014/09/29 Python
Python hashlib模块用法实例分析
2018/06/12 Python
为什么str(float)在Python 3中比Python 2返回更多的数字
2018/10/16 Python
Python3实现爬虫爬取赶集网列表功能【基于request和BeautifulSoup模块】
2018/12/05 Python
python 为什么说eval要慎用
2019/03/26 Python
python之生产者消费者模型实现详解
2019/07/27 Python
python写程序统计词频的方法
2019/07/29 Python
详解pyinstaller生成exe的闪退问题解决方案
2020/06/19 Python
Python dict的常用方法示例代码
2020/06/23 Python
Original Penguin美国官网:布拉德皮特、强尼德普喜爱的服装品牌
2016/10/25 全球购物
分解成质因数(如435234=251*17*17*3*2,据说是华为笔试题)
2014/07/16 面试题
优秀共产党员先进事迹
2014/01/27 职场文书
浪漫婚礼主持词
2014/03/14 职场文书
消防安全责任书
2014/04/14 职场文书
小学生环保演讲稿
2014/04/25 职场文书
幼师自荐信范文
2015/03/06 职场文书