python自定义装饰器实例详解

  

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

  

先看一个例子

        def德科(函数):   之前打印(“myfunc()被称为”。)   函数()   打印(“myfunc之后()称为”。)   回归函数   @deco   def myfunc ():   打印(“myfunc()称为”。)   # myfunc=德科(myfunc) #与上面的@deco等价   myfunc ()   打印(“* * * * * * * * * * *”)   myfunc ()      之前      

会发现,输出为

  
  

之前myfunc()调用。
  myfunc()调用。
  后myfunc()调用。
  myfunc()调用。
  * * * * * * * * * * *
  

myfunc()调用。      

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

  

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

  

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

        def德科(函数):   def包装器(* args, * * kwargs): # * args, * * kwargs用于接收func的参数   之前打印(“myfunc()被称为”。)   func (* args, * * kwargs)   打印(“myfunc之后()称为”。)   返回包装   @deco   def myfunc (a, b):   打印(a + b)   # myfunc=德科(myfunc) #与上面的@deco等价   myfunc (1、2)   打印(“* * * * * * * * * * *”)   myfunc (3、4)      之前      

该代码输出结果为

  
  

之前myfunc()调用。
  3
  后myfunc()调用。
  * * * * * * * * * * *
  之前myfunc()调用。
  7
  

myfunc后()调用。      

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

  

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

        def德科(函数):   def包装器(* args, * * kwargs): # * args, * * kwargs用于接收func的参数   打印(“包装器的地址:“哦,包装)   func (* args, * * kwargs)   打印(“func的地址:”函数)   返回包装   @deco   def myfunc (a, b):   打印(“myfunc的地址:“,myfunc)   打印(a + b)   # myfunc=德科(myfunc) #与上面的@deco等价   myfunc (1、2)   打印(“* * * * * * * * * * *”)   打印(“修改后myfunc的地址:“,myfunc)      之前      

运行结果:

  
  

包装的地址:& lt;装饰功能灵活,locals>。包装在0 x0000023aa9ff58c8>
  myfunc的地址:& lt;装饰功能灵活,locals>。包装在0 x0000023aa9ff58c8>
  3
  func的地址:& lt;函数myfunc 0 x0000023aa9ff5840>
  * * * * * * * * * * *
  修改后myfunc的地址:& lt;装饰功能灵活,locals>。包装在0 x0000023aa9ff58c8>

     

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

python自定义装饰器实例详解