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文件中文编码问题
Nov 22 Python
Python 解决中文写入Excel时抛异常的问题
May 03 Python
Python实现的多叉树寻找最短路径算法示例
Jul 30 Python
python pandas写入excel文件的方法示例
Jun 25 Python
django中账号密码验证登陆功能的实现方法
Jul 15 Python
如何使用Python破解ZIP或RAR压缩文件密码
Jan 09 Python
Python面向对象程序设计之类和对象、实例变量、类变量用法分析
Mar 23 Python
Python实现AES加密,解密的两种方法
Oct 03 Python
python 从list中随机取值的方法
Nov 16 Python
使用python画出逻辑斯蒂映射(logistic map)中的分叉图案例
Dec 11 Python
python 实现百度网盘非会员上传超过500个文件的方法
Jan 07 Python
PyTorch 实现L2正则化以及Dropout的操作
May 27 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获取汉字首字母的函数
2013/11/07 PHP
用Zend Studio+PHPnow+Zend Debugger搭建PHP服务器调试环境步骤
2014/01/19 PHP
Yii核心组件AssetManager原理分析
2014/12/02 PHP
Symfony2联合查询实现方法
2016/03/18 PHP
PHP后端银联支付及退款实例代码
2017/06/23 PHP
Laravel 自带的Auth验证登录方法
2019/09/30 PHP
JavaScript单元测试ABC
2012/04/12 Javascript
js 控制下拉菜单刷新的方法
2013/03/03 Javascript
谈谈关于JavaScript 中的 MVC 模式
2013/04/11 Javascript
NodeJs中的VM模块详解
2015/05/06 NodeJs
smartcrop.js智能图片裁剪库
2015/10/14 Javascript
JavaScript function函数种类详解
2016/02/22 Javascript
AngularJS基础 ng-href 指令用法
2016/08/01 Javascript
谈谈target=_new和_blank的不同之处
2016/10/25 Javascript
详解 vue better-scroll滚动插件排坑
2018/02/08 Javascript
vue 全选与反选的实现方法(无Bug 新手看过来)
2018/02/09 Javascript
JS严格模式知识点总结
2018/02/27 Javascript
JavaScript轮播停留效果的实现思路
2018/05/24 Javascript
layui上传图片到服务器的非项目目录下的方法
2019/09/26 Javascript
Python 2.7.x 和 3.x 版本的重要区别小结
2014/11/28 Python
使用Python3中的gettext模块翻译Python源码以支持多语言
2015/03/31 Python
详细介绍Python中的偏函数
2015/04/27 Python
python+numpy+matplotalib实现梯度下降法
2018/08/31 Python
Python面向对象程序设计类的封装与继承用法示例
2019/04/12 Python
python程序中的线程操作 concurrent模块使用详解
2019/09/23 Python
基于css3仿造window7的开始菜单
2010/06/17 HTML / CSS
欧洲最大的笔和书写专家:The Pen Shop
2017/03/19 全球购物
“型”走纽约上东区:Sam Edelman
2017/04/02 全球购物
美国女性奢华品牌精品店:INTERMIX
2017/10/12 全球购物
免税水晶:Duty Free Crystal
2019/05/13 全球购物
时尚孕妇装:HATCH Collection
2019/09/24 全球购物
乡镇党委书记第三阶段个人整改措施
2014/09/16 职场文书
运动会通讯稿200字
2015/07/20 职场文书
MySQL中你可能忽略的COLLATION实例详解
2021/05/12 MySQL
Python使用openpyxl批量处理数据
2021/06/23 Python
css让页脚保持在底部位置的四种方案
2022/07/23 HTML / CSS