当前位置: 首页 > 编程笔记 >

python 自定义装饰器实例详解

慕容渊
2023-03-14
本文向大家介绍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装饰器实例大详解,包括了python装饰器实例大详解的使用技巧和注意事项,需要的朋友参考一下 一.作用域 在python中,作用域分为两种:全局作用域和局部作用域。  全局作用域是定义在文件级别的变量,函数名。而局部作用域,则是定义函数内部。  关于作用域,我们要理解两点:     a.在全局不能访问到局部定义的变量     b.在局部能够访问到全局定义的变量,但是不能修

  • 本文向大家介绍实例详解Python装饰器与闭包,包括了实例详解Python装饰器与闭包的使用技巧和注意事项,需要的朋友参考一下 闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。 变量作用域规则 首先,在函数中是能访问全局变量的: 然后,在一个嵌套函数中,内层函数能够访问在外层函数中定义的局部变量: 闭包 上面的嵌套函数就是闭包。 闭包 是指延伸了作用域的函数,在

  • 问题内容: 我受够了在函数中不断重复输入相同的重复命令。我想知道我是否可以写一个装饰器为我做这项工作。这是我的问题的一个示例: 有什么方法可以自动将所有传递给函数的参数变成具有相同名称的实例变量?例如: 哪里会自动设置和。我该怎么办? 谢谢! 编辑:我应该提到我使用CPython 2.7。 问题答案: 这是我第一次尝试装饰器: 编辑第二尝试:我添加了处理变量的默认值和检查有效的关键字。 [编辑3:

  • Nest 是基于 装饰器 这种语言特性而创建的。在很多常用的编程语言中 装饰器 都是一个很大众的概念,但在 JavaScript 语言中这个概念却比较新。所以为了更好地理解装饰器是如何工作的,你应该看看 这篇 文章。下面给出一个简单的定义: ES2016 的装饰器是一个可以将目标对象,名称和属性描述符作为被修饰方法(returns function)的参数的表达式。你可以通过装饰器前缀 @ 来使用

  • 本文向大家介绍Python闭包和装饰器用法实例详解,包括了Python闭包和装饰器用法实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python闭包和装饰器用法。分享给大家供大家参考,具体如下: Python的装饰器的英文名叫Decorator,作用是完成对一些模块的修饰。所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装

  • 本文向大家介绍python自定义异常实例详解,包括了python自定义异常实例详解的使用技巧和注意事项,需要的朋友参考一下 python自定义异常实例详解          本文通过两种方法对Python 自定义异常进行讲解,第一种:创建一个新的exception类来拥有自己的异常,第二种:raise 唯一的一个参数指定了要被抛出的异常 1、可以通过创建一个新的exception类来拥有自己的异常

  • 本文向大家介绍Python类装饰器实现方法详解,包括了Python类装饰器实现方法详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python类装饰器。分享给大家供大家参考,具体如下: 编写类装饰器 类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。 单体类 由于类装饰器可以拦截实例创建调用,所以它们可以用来管理一个类的所有实例,

  • 问题内容: 我正在使用django和celery(django-celery)进行项目。我们的团队决定将所有数据访问代码包装在其中(不要像django这样包装到Manager中),而将代码放入(应用程序名称)中,仅处理用celery组装和执行任务(因此我们没有django在这一层的ORM依赖性)。 在我的,我有这样的事情: 在我的中,我喜欢将它们包装成任务(然后可以使用这些任务来完成更复杂的任务)