python 自定义装饰器实例详解

 更新时间:2019年07月20日 16:02:47   作者:Panda_Boy_yi  
这篇文章主要介绍了python 自定义装饰器,结合实例形式分析了Python自定义装饰器的功能、原理、用法及相关操作注意事项,需要的朋友可以参考下

本文实例讲述了python 自定义装饰器。分享给大家供大家参考,具体如下:

先看一个例子

def deco(func):
  print("before myfunc() called.")
  func()
  print("after myfunc() called.")
  return func
@deco
def myfunc():
  print("myfunc() called.")
# myfunc = deco(myfunc) # 与上面的@deco等价
myfunc()
print("***********")
myfunc()

会发现,输出为

before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
***********
myfunc() called.

这就是说,装饰器里面的东西只调用了一次,为什么呢?

是因为,在myfunc()函数的定义前面加一句@deco,本质上完全等价于在出现def myfunc()后,先将下面所有内容的首地址传递给func,然后紧接着加上一句 myfunc = deco(myfunc)。执行这句话,表示func代表了本来定义的myfunc()的函数体,同时函数myfunc()的地址传递给deco()函数,即 myfunc -> func,这里就相当于myfunc的值与func的值完全相同了。然后执行装饰器里面的内容,最后返回给func,传递给myfunc。接下来在调用myfunc()的时候,打印输出“myfunc() called”。第二次调用myfunc()函数的时候,依然只打印输出“myfunc() called”。为什么第二次没有执行装饰器里面的内容呢?是因为,myfunc = deco(myfunc)这句话只执行了一次,而这句话,才是真正执行装饰器里面的内容的话。

上面的代码表示,装饰器相当于只对第一次调用他的函数进行了装饰,那么,怎么对每次调用的函数都装饰呢?接着看

def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的参数
    print("before myfunc() called.")
    func(*args, **kwargs)
    print("after myfunc() called.")
  return wrapper
@deco
def myfunc(a, b):
  print(a+b)
# myfunc = deco(myfunc) # 与上面的@deco等价
myfunc(1, 2)
print("***********")
myfunc(3, 4)

该代码输出结果为

before myfunc() called.
3
after myfunc() called.
***********
before myfunc() called.
7
after myfunc() called.

我们说了,在myfunc()函数的定义前面加一句@deco,本质上完全等价于在出现def?myfunc()后,先将下面所有内容的首地址传递给func,然后紧接着加上一句 myfunc = deco(myfunc)。执行myfunc(1, 2)命令的时候,myfunc函数体的地址早已经传递给了deco()函数,返回的是wrapper。这是myfunc所代表的地址不再是原来的myfunc的地址,而是wrapper函数的地址。所以,以后凡是出现myfunc()的地方,都是在调用wrapper()函数。即myfunc(1, 2)就是wrapper(1, 2),所以每次调用myfunc()时候,装饰器里面的内容都会被执行了。而wrapper()函数体里面的func,就代表了原来myfunc()的函数体。

怎么进一步理解“在出现def?myfunc()后,先将下面所有内容的首地址传递给func”这句话呢?看:

def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的参数
    print("wrapper的地址:", wrapper)
    func(*args, **kwargs)
    print("func的地址:", func)
  return wrapper
@deco
def myfunc(a, b):
  print("myfunc的地址:",myfunc)
  print(a+b)
# myfunc = deco(myfunc) # 与上面的@deco等价
myfunc(1, 2)
print("***********")
print("修改后myfunc的地址:",myfunc)

运行结果:

wrapper的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>
myfunc的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>
3
func的地址: <function myfunc at 0x0000023AA9FF5840>
***********
修改后myfunc的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>

程序执行到myfunc(1,2)的时候,本质上是在执行wrapper(1, 2),于是先输出wrapper的地址,再执行func()函数。执行func()函数的时候,输出myfunc()的地址,(可见,此时myfunc的值与wrapper的是相等),再打印3。当输出func()函数的地址,可见func()函数的地址与myfunc()函数的地址不一样了!!!!这就是说,原来定义的myfunc()函数的函数体,已经属于func了,而不属于myfunc了!!

进一步见证奇迹!!

def deco(func):
  def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的参数
    pass
  return wrapper
@deco
def myfunc(a, b):
  print(a+b)
myfunc(1, 2)

该代码没有任何输出。那是因为,执行myfunc(1, 2)的时候,本质上是执行wrapper(1, 2)。而wrapper(1, 2)又不干任何事情,所以没有输出。至于print(a+b)这句话,他的地址已经属于func了。

带参数的装饰器,可以参见其他文章

更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程

希望本文所述对大家Python程序设计有所帮助。

相关文章

  • Python应用自动化部署工具Fabric原理及使用解析

    Python应用自动化部署工具Fabric原理及使用解析

    这篇文章主要介绍了Python应用自动化部署工具Fabric原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • Django ModelForm组件原理及用法详解

    Django ModelForm组件原理及用法详解

    这篇文章主要介绍了Django ModelForm组件原理及用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • python基础_文件操作实现全文或单行替换的方法

    python基础_文件操作实现全文或单行替换的方法

    下面小编就为大家带来一篇python基础_文件操作实现全文或单行替换的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Python实现原神抽卡的方法

    Python实现原神抽卡的方法

    这篇文章主要为大家介绍了Python实现原神抽卡的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • python银行卡号码校验Luhn模10算法

    python银行卡号码校验Luhn模10算法

    这篇文章主要为大家介绍了python银行卡号码校验Luhn模10算法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Python Tricks 使用 pywinrm 远程控制 Windows 主机的方法

    Python Tricks 使用 pywinrm 远程控制 Windows 主机的方法

    这篇文章主要介绍了Python Tricks 使用 pywinrm 远程控制 Windows 主机的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 如何在Python中引入和使用浏览器驱动

    如何在Python中引入和使用浏览器驱动

    本文介绍了如何在Python中引入和使用浏览器驱动,主要步骤包括安装Selenium库、下载并配置浏览器驱动路径、编写Python代码启动浏览器以及结束操作后关闭浏览器
    2025-01-01
  • Python if else语句对缩进的要求

    Python if else语句对缩进的要求

    这篇文章主要介绍了Python if else语句对缩进的要求,前面的一篇文章展示了选择结构的三种基本形式,并给出了实例演示,这篇文章基于上一篇内容继续对Python if else语句对缩进进行描述,需要的小伙伴可以参考一下
    2022-03-03
  • Python restful框架接口开发实现

    Python restful框架接口开发实现

    这篇文章主要介绍了Python restful框架接口开发实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • python实现跨年烟花动态效果

    python实现跨年烟花动态效果

    这篇文章主要介绍了python实现跨年烟花的动态效果,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01

最新评论