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实现在字符串中查找子字符串的方法
Jul 11 Python
Python 3中print函数的使用方法总结
Aug 08 Python
Python基于mysql实现学生管理系统
Feb 21 Python
Pycharm远程调试原理及具体配置详解
Aug 08 Python
详解有关PyCharm安装库失败的问题的解决方法
Feb 02 Python
简单了解Java Netty Reactor三种线程模型
Apr 26 Python
python爬虫请求头设置代码
Jul 28 Python
python dict如何定义
Sep 02 Python
python实现人工蜂群算法
Sep 18 Python
Pycharm中如何关掉python console
Oct 27 Python
Django数据库迁移常见使用方法
Nov 12 Python
Python 的演示平台支持 WSGI 接口的应用
Apr 20 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下通过IP获取地理位置的代码(小偷程序)
2011/06/09 PHP
用Json实现PHP与JavaScript间数据交换的方法详解
2013/06/20 PHP
浅析php过滤html字符串,防止SQL注入的方法
2013/07/02 PHP
php遍历目录方法小结
2015/03/10 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
使用CSS3实现字体颜色渐变的实现
2021/03/09 HTML / CSS
麻雀虽小五脏俱全 Dojo自定义控件应用
2010/09/04 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
2013/01/23 Javascript
node.js中的emitter.emit方法使用说明
2014/12/10 Javascript
JavaScript实现Java中StringBuffer的方法
2015/02/09 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
2017/12/06 Javascript
弱类型语言javascript开发中的一些坑实例小结【变量、函数、数组、对象、作用域等】
2019/08/07 Javascript
vue打开其他项目页面并传入数据详解
2020/11/25 Vue.js
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
Python中dictionary items()系列函数的用法实例
2014/08/21 Python
tensorflow 用矩阵运算替换for循环 用tf.tile而不写for的方法
2018/07/27 Python
用Python shell简化开发
2018/08/08 Python
python 把列表转化为字符串的方法
2018/10/23 Python
python 字符串追加实例
2019/07/20 Python
Python使用lambda表达式对字典排序操作示例
2019/07/25 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
2020/01/06 Python
将keras的h5模型转换为tensorflow的pb模型操作
2020/05/25 Python
澳大利亚现代波西米亚风格女装网站:Bohemian Traders
2018/04/16 全球购物
YSL圣罗兰美妆官方旗舰店:购买YSL口红
2018/04/16 全球购物
亚洲独特体验旅游专家:eOasia
2018/08/15 全球购物
局域网定义和特性
2016/01/23 面试题
学期评语大全
2014/04/30 职场文书
银行爱岗敬业演讲稿
2014/05/05 职场文书
支部组织生活会方案
2014/06/10 职场文书
祖国在我心中演讲稿200字
2014/08/28 职场文书
五四演讲稿范文
2014/09/03 职场文书
2014大四本科生自我鉴定总结
2014/10/04 职场文书
2014年库房工作总结
2014/11/26 职场文书
商务司机岗位职责
2015/04/10 职场文书
背起爸爸上学观后感
2015/06/08 职场文书
王亚平太空授课观后感
2015/06/12 职场文书