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中字符编码简介、方法及使用建议
Jan 08 Python
使用PyCharm配合部署Python的Django框架的配置纪实
Nov 19 Python
python黑魔法之参数传递
Feb 12 Python
Python画图学习入门教程
Jul 01 Python
Python实例方法、类方法、静态方法的区别与作用详解
Mar 25 Python
numpy 声明空数组详解
Dec 05 Python
centos7中安装python3.6.4的教程
Dec 11 Python
基于python3的socket聊天编程
Feb 17 Python
Python读取yaml文件的详细教程
Jul 21 Python
python判断all函数输出结果是否为true的方法
Dec 03 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
Jan 05 Python
python和Appium的移动端多设备自动化测试框架
Apr 26 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限制页面只能在微信自带浏览器访问的代码
2014/01/15 PHP
接收键盘指令的脚本
2006/06/26 Javascript
onpropertypchange
2006/07/01 Javascript
JavaScript 仿关机效果的图片层
2008/12/26 Javascript
javascript中的作用域scope介绍
2010/12/28 Javascript
$.getJSON在IE下失效的原因分析及解决方法
2013/06/16 Javascript
JavaScript定义类的几种方式总结
2014/01/06 Javascript
javascript实现日期格式转换
2014/12/16 Javascript
详解AngularJS中自定义指令的使用
2015/06/17 Javascript
CascadeView级联组件实现思路详解(分离思想和单链表)
2016/04/12 Javascript
微信小程序 progress组件详解及实例代码
2016/10/25 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
ES6 Promise对象概念与用法分析
2017/04/01 Javascript
使用OPENLAYERS3实现点选的方法
2020/09/24 Javascript
关于Vue实现组件信息的缓存问题
2017/08/23 Javascript
js 显示日期时间的实例(时间过一秒加1)
2017/10/25 Javascript
vue router 配置路由的方法
2018/07/26 Javascript
微信小程序实现预览图片功能
2020/10/22 Javascript
深入Node TCP模块的理解
2019/03/13 Javascript
微信小程序自定义弹出模态框禁止底部滚动功能
2020/03/09 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
2020/04/10 Javascript
[17:00]DOTA2 HEROS教学视频教你分分钟做大人-帕克
2014/06/10 DOTA
[01:07:11]Secret vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python实现登录人人网并抓取新鲜事的方法
2015/05/11 Python
python实现判断数组是否包含指定元素的方法
2015/07/15 Python
Python实现学校管理系统
2018/01/11 Python
使用Python将字符串转换为格式化的日期时间字符串
2019/09/01 Python
python scipy卷积运算的实现方法
2019/09/16 Python
python 实现Flask中返回图片流给前端展示
2020/01/09 Python
详解Python修复遥感影像条带的两种方式
2020/02/23 Python
pyinstaller将含有多个py文件的python程序做成exe
2020/04/29 Python
锐步美国官方网站:Reebok美国
2018/01/10 全球购物
大学四年规划书范文
2013/12/27 职场文书
高校自主招生教师推荐信
2015/03/23 职场文书
狼牙山五壮士观后感
2015/06/09 职场文书
SONY AN-LP1 短波有源天线放大器
2021/04/22 无线电