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读写excel的方法
Nov 18 Python
Python实现批量将word转html并将html内容发布至网站的方法
Jul 14 Python
简单掌握Python中glob模块查找文件路径的用法
Jul 05 Python
Python验证文件是否可读写代码分享
Dec 11 Python
实用自动化运维Python脚本分享
Jun 04 Python
Python异常处理例题整理
Jul 07 Python
python GUI图形化编程wxpython的使用
Jul 19 Python
pytorch多GPU并行运算的实现
Sep 27 Python
解决django-xadmin列表页filter关联对象搜索问题
Nov 15 Python
python实现同一局域网下传输图片
Mar 20 Python
简单了解Django项目应用创建过程
Jul 06 Python
python pymysql库的常用操作
Oct 16 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/08/03 PHP
PHP实现HTML页面静态化的方法
2015/11/04 PHP
php中final关键字用法分析
2016/12/07 PHP
基于laravel where的高级使用方法
2019/10/10 PHP
php pdo连接数据库操作示例
2019/11/18 PHP
50个优秀经典PHP算法大集合 附源码
2020/08/26 PHP
JQuery Tips(4) 一些关于提高JQuery性能的Tips
2009/12/19 Javascript
jqGrid增加时--判断开始日期与结束日期(实例解析)
2013/11/08 Javascript
js中substr,substring,indexOf,lastIndexOf的用法小结
2013/12/27 Javascript
js数组去重的常用方法总结
2014/01/24 Javascript
JavaScript框架(iframe)操作总结
2014/04/16 Javascript
初步认识JavaScript函数库jQuery
2015/06/18 Javascript
基于jquery实现放大镜效果
2015/08/17 Javascript
JS倒计时实例_天时分秒
2017/08/22 Javascript
JavaScript编写棋盘覆盖代码详解
2017/08/28 Javascript
bootstrap3中container与container_fluid外层容器的区别讲解
2017/12/04 Javascript
浅谈ajax在jquery中的请求和servlet中的响应
2018/01/22 jQuery
layer.js open 隐藏滚动条的例子
2019/09/05 Javascript
详解JavaScript 的执行机制
2020/09/18 Javascript
[02:08]我的刀塔不可能这么可爱 胡晓桃_1
2014/06/20 DOTA
python删除文件示例分享
2014/01/28 Python
Python如何快速实现分布式任务
2017/07/06 Python
树莓派+摄像头实现对移动物体的检测
2019/06/22 Python
Python命令行参数argv和argparse该如何使用
2021/02/08 Python
matplotlib绘制正余弦曲线图的实现
2021/02/22 Python
HTML5 script元素async、defer异步加载使用介绍
2013/08/23 HTML / CSS
GWT都有什么特性
2016/12/02 面试题
生日邀请函范文
2014/01/13 职场文书
学生会主席事迹材料
2014/01/28 职场文书
个人求职信范文
2014/05/24 职场文书
客房领班岗位职责
2015/02/11 职场文书
详解nodejs内置模块
2021/05/06 NodeJs
深入理解Vue的数据响应式
2021/05/15 Vue.js
Java 数组的使用
2022/05/11 Java/Android
apache虚拟主机配置的三种方式(小结)
2022/07/23 Servers
JS前端使用canvas实现物体的点选示例
2022/08/05 Javascript