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之Python安装
Sep 12 Python
Django中的CACHE_BACKEND参数和站点级Cache设置
Jul 23 Python
Python深入06——python的内存管理详解
Dec 07 Python
Python使用PDFMiner解析PDF代码实例
Mar 27 Python
Python实现计算两个时间之间相差天数的方法
May 10 Python
Python数据分析之双色球统计单个红和蓝球哪个比例高的方法
Feb 03 Python
Python实现的基于优先等级分配糖果问题算法示例
Apr 25 Python
解决PyCharm同目录下导入模块会报错的问题
Oct 13 Python
python脚本开机自启的实现方法
Jun 28 Python
python global和nonlocal用法解析
Feb 03 Python
Python实现AES加密,解密的两种方法
Oct 03 Python
Python常用base64 md5 aes des crc32加密解密方法汇总
Nov 06 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动态生成虚拟现实VRML网页
2006/10/09 PHP
PHP导入Excel到MySQL的方法
2011/04/23 PHP
使用php get_headers 判断URL是否有效的解决办法
2013/04/27 PHP
织梦sitemap地图实时推送给百度的教程
2015/08/03 PHP
PHP实现QQ快速登录的方法
2016/09/28 PHP
ThinkPHP打水印及设置水印位置的方法
2016/10/14 PHP
qTip2 精致的基于jQuery提示信息插件
2012/02/17 Javascript
一个基于jquery的文本框记数器
2012/09/19 Javascript
深入探究JavaScript中for循环的效率问题及相关优化
2016/03/13 Javascript
AngularJS 中的指令实践开发指南(一)
2016/03/20 Javascript
关于JS变量和作用域详解
2016/07/28 Javascript
JS基于正则表达式的替换操作(replace)用法示例
2017/04/28 Javascript
微信小程序图片宽100%显示并且不变形
2017/06/21 Javascript
学习jQuery中的noConflict()用法
2018/09/28 jQuery
谈谈React中的Render Props模式
2018/12/06 Javascript
vue 实现搜索的结果页面支持全选与取消全选功能
2019/05/10 Javascript
解决layui弹框失效的问题
2019/09/09 Javascript
vue使用better-scroll实现滑动以及左右联动
2020/06/30 Javascript
JavaScript DOM常用操作代码汇总
2020/07/03 Javascript
Vue+Openlayers自定义轨迹动画
2020/09/24 Javascript
Python pickle模块用法实例
2015/04/14 Python
python实现爬虫统计学校BBS男女比例(一)
2015/12/31 Python
Python数据结构与算法之图结构(Graph)实例分析
2017/09/05 Python
python实现的MySQL增删改查操作实例小结
2018/12/19 Python
python3 实现的对象与json相互转换操作示例
2019/08/17 Python
Python-jenkins 获取job构建信息方式
2020/05/12 Python
python给list排序的简单方法
2020/12/10 Python
英国一家集合了众多有才华设计师品牌的奢侈店:Wolf & Badger
2018/04/18 全球购物
语文教育专业推荐信范文
2013/11/25 职场文书
教师校本培训方案
2014/02/26 职场文书
销售员试用期自我评价
2014/09/15 职场文书
银行实习推荐信
2015/03/27 职场文书
小学运动会报道稿
2015/07/22 职场文书
Mysql文件存储图文详解
2021/06/01 MySQL
使用nginx配置访问wgcloud的方法
2021/06/26 Servers
JavaScript函数柯里化
2021/11/07 Javascript