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读取ini文件、操作mysql、发送邮件实例
Jan 01 Python
python开发中range()函数用法实例分析
Nov 12 Python
使用Python的Flask框架表单插件Flask-WTF实现Web登录验证
Jul 12 Python
Pycharm无法使用已经安装Selenium的解决方法
Oct 13 Python
PyCharm代码回滚,恢复历史版本的解决方法
Oct 22 Python
python正向最大匹配分词和逆向最大匹配分词的实例
Nov 14 Python
Python实现某论坛自动签到功能
Aug 20 Python
Python之Django自动实现html代码(下拉框,数据选择)
Mar 13 Python
简单的Python人脸识别系统
Jul 14 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
Mar 04 Python
python 利用PyAutoGUI快速构建自动化操作脚本
May 31 Python
浅谈怎么给Python添加类型标注
Jun 08 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
mysql 搜索之简单应用
2007/04/27 PHP
PHP一些常用的正则表达式字符的一些转换
2008/07/29 PHP
PHP7.0版本备注
2015/07/23 PHP
PHP开发中AJAX技术的简单应用
2015/12/11 PHP
如何让PHP编码更加好看利于阅读
2019/05/12 PHP
JS request函数 用来获取url参数
2010/05/17 Javascript
Javascript加载速度慢的解决方案
2014/03/11 Javascript
javascript事件冒泡详解和捕获、阻止方法
2014/04/12 Javascript
jQuery页面加载初始化常用的三种方法
2014/06/04 Javascript
js完美实现@提到好友特效(兼容各大浏览器)
2015/03/16 Javascript
详解js私有作用域中创建特权方法
2016/01/25 Javascript
JavaScript 函数的执行过程
2016/05/09 Javascript
用JS实现简单的登录验证功能
2017/07/28 Javascript
NodeJS收发GET和POST请求的示例代码
2017/08/25 NodeJs
js的函数的按值传递参数(实例讲解)
2017/11/16 Javascript
解决layui中的form表单与button的点击事件冲突问题
2018/08/15 Javascript
vue组件开发之用户无限添加自定义填写表单的方法
2018/08/28 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
2018/09/14 Javascript
node.js使用redis储存session的方法
2018/09/26 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
js找出5个数中最大的一个数和倒数第二大的数实现方法示例小结
2020/03/04 Javascript
vue实现输入框自动跳转功能
2020/05/20 Javascript
JavaScript逻辑运算符相关总结
2020/09/04 Javascript
python中循环语句while用法实例
2015/05/16 Python
浅谈python字符串方法的简单使用
2016/07/18 Python
python多环境切换及pyenv使用过程详解
2019/09/27 Python
python 3.74 运行import numpy as np 报错lib\site-packages\numpy\__init__.py
2019/10/06 Python
python pygame实现球球大作战
2019/11/25 Python
Bootstrap 学习分享
2012/11/12 HTML / CSS
HTML5 绘制图像(上)之:关于canvas元素引领下一代web页面的问题
2013/04/24 HTML / CSS
学生会竞选演讲稿怎么写
2014/08/26 职场文书
三潭印月的导游词
2015/02/12 职场文书
房地产销售助理岗位职责
2015/04/14 职场文书
分享CSS盒子模型隐藏的几种方式
2022/02/28 HTML / CSS
MySQL时区造成时差问题
2022/04/13 MySQL
js 实现验证码输入框示例详解
2022/09/23 Javascript