python装饰器用法,python 类装饰器和函数装饰器区别

  python装饰器用法,python 类装饰器和函数装饰器区别

  本文为大家带来一些关于python的知识,主要梳理了decorator函数的相关问题,包括decorator的形成过程、本质与功能、高级与优化等。下面就来看看吧,希望对你有帮助。

  推荐:python

  假设我写了一个函数f

  def f():

  print(hello )之后,我想知道执行这个函数需要的时间。很简单。我只需要将代码改为如下

  导入时间

  def f():

  Start=time.time() #获取程序执行的开始时间

  打印(“你好”)

  End=time.time() #获取程序执行的结束时间。

  Print(end-start) #获取函数F执行所需的时间

  但是我已经写了无数的函数F2,F3.FN。我想知道每个函数执行所需要的时间,那么如果都像上面那样改了岂不是很烦?不行,因为太麻烦了。那我该怎么办?于是灵机一动,写了一个定时器函数。

  导入时间

  定义定时器(功能):

  start=time.time()

  函数()

  print(time.time() - start)

  def f():

  打印(“你好”)

  定义f2():

  打印( xorld )

  计时器(f)

  定时器(f2)这个看起来是不是简单多了?不管我们写多少函数,都可以调用这个计时函数来计算函数的执行时间。

  但如果我只是想用原来的方式调用这个函数f1(),f2(),fn(),函数也可以在原来输出结果不变的前提下增加计算时间的函数,而不是调用timer(f),这样timer(f2)就可以计算时间了,怎么办?

  通过阅读下面的装饰函数,你会知道如何解决这个问题。

  00-1010下面是解决上述问题的简单版本的代码:

  导入时间

  def f():

  打印(“你好”)

  定义定时器(功能):

  内部定义():

  start=time.time()

  函数()

  print(time.time() - start)

  返回内部

  f=定时器(f)

  f()还是那句话,我只是想用原来的方式调用这个函数F1(),F2()和FN()。函数也可以在原来执行输出结果不变的前提下增加计算时间的功能,但是在函数F执行之前我还是要在这串代码中写f=timer(f)。你觉得它碍眼吗?Python开发者也觉得碍眼,所以python开发者给我们提供了一个语法糖来解决这个问题!

  00-1010用@timmer代替f=timer(f),这是语法上的糖。

  导入时间

  定义定时器(功能):

  内部定义():

  start=time.time()

  函数()

  print(time.time() - start)

  返回内部

  @timer #==写这句话相当于执行f=timer(f)

  def f():

  打印(“你好”)

  F()

一、装饰器 —— 形成过程

1。本质

  装饰器的本质是一个闭包函数。

  2.功能

  在不修改原函数及其调用方式的情况下,扩展原函数的功能。

  00-1010

二、装饰器 —— 初识语法糖

我们刚才写的decorators都是没有参数的修饰函数。我们现在应该怎么做才能用参数来修饰一个函数呢?

  ="brush:php;toolbar:false">import time

  def timer(func):

   def inner(a):

   start = time.time()

   func(a)

   print(time.time() - start)

   return inner

  @timer

  def f(a):

   print(a)

  f('hello')

  • 2、装饰多个带有不同参数但无返回值的函数

其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢,比如 函数func1有两个参数func1(a ,b),函数func 2只有一个参数func2(a), 且它们都想用这个装饰器装饰,做到计算函数执行时间?这怎么办呢?那就用下面代码。

  

import time

  def timer(func):

   def inner(*args,**kwargs):

   start = time.time()

   re = func(*args,**kwargs)

   print(time.time() - start)

   return re

   return inner

  @timer #==> func1 = timer(func1)

  def func1(a,b):

   print('in func1')

  @timer #==> func2 = timer(func2)

  def func2(a):

   print('in func2 and get a:%s'%(a))

   return 'fun2 over'

  func1('aaaaaa','bbbbbb')

  print(func2('aaaaaa'))

  输出结果:

  in func1

  0.0

  in func2 and get a:aaaaaa

  0.0

  fun2 over

  • 3、装饰多个带有不同参数且有返回值的函数

现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?用上面的代码你就拿不到返回值了那究竟要如何解决这个问题呢?那就看下面的代码吧!

  

import time

  def timer(func):

   def inner(*args,**kwargs):

   start = time.time()

   re = func(*args,**kwargs)

   print(time.time() - start)

   return re

   return inner

  @timer #==> func2 = timer(func2)

  def func2(a):

   print('in func2 and get a:%s'%(a))

   return 'fun2 over'

  func2('aaaaaa')

  print(func2('aaaaaa'))

  输出结果:

  in func2 and get a:aaaaaa

  0.0

  in func2 and get a:aaaaaa

  0.0

  fun2 over

  • 4、多个装饰器装饰同一个函数

有些时候,我们也会用到多个装饰器装饰同一个函数的情况。

  

ef wrapper1(func): #func ----- f

   def inner1():

   print('wrapper1 ,before func')

   func()

   print('wrapper1 ,after func')

   return inner1

  def wrapper2(func):

   def inner2():

   print('wrapper2 ,before func')

   func()

   print('wrapper2 ,after func')

   return inner2

  @wrapper2 #f = wrapper2(f) ----->> wrapper2(inner1) == inner2

  @wrapper1 #f = wrapper1(f) = inner

  def f():

   print('in f')

  f() #===>>inner2

  #多个装饰器装饰同一个函数

  输出结果:

  wrapper2 ,before func

  wrapper1 ,before func

  in f

  wrapper1 ,after func

  wrapper2 ,after func



五、装饰器 —— 装饰器进阶与优化

  • 1、带参数的装饰器

上面那个装饰器已经非常beautiful了,但是还有一个问题,如果我给代码中无数个函数都加了@timer这个语法糖,如果之后我又不想用它了那岂不是又要每个去将它注释,没日没夜忙活3天?岂不是特别麻烦,为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除 我们引入带参数的装饰器概念

  

'''

  为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除

  我们引入带参数的装饰器概念

  '''

  import time

  '''FLAGE的目的是用它控制装饰器的开关,

  那么当我们不用的时候就不要一个一个去注释只需将True改为False就行'''

  FLAGE = True

  def timmer_out(flag):

   def timmer(func):

   def inner(*args,**kwargs):

   if flag:

   start = time.time()

   ret = func(*args,**kwargs)

   end = time.time()

   print(end - start)

   return ret

   else:

   ret = func(*args, **kwargs)

   return ret

   return inner

   return timmer

  @timmer_out(FLAGE)

  #timmer_out(FLAGE)

  # 也相当于执行 timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha))

  def wahaha():

   time.sleep(0.1) #不休息的话函数执行的太快难以计算时间

   print('wahahahahahaha')

  wahaha()

  @timmer_out(FLAGE)

  def erguotou():

   time.sleep(0.1) #不休息的话函数执行的太快难以计算时间

   print('erguotoutoutou')

  erguotou()

  输出结果:

  wahahahahahaha

  0.10152268409729004

  erguotoutoutou

  0.10795140266418457

  • 2、防止函数必要信息失效

'''

  print(wahaha.__name__) #查看字符串格式的函数名

  print(wahaha.__doc__) #查看一个函数的注释

  '''

  #下面用__name__查看holiday的函数名

  from functools import wraps

  def wrapper(func):

   @wraps(func) #加在最内层函数正上方

   def inner(*args,**kwargs):

   print('在被装饰的函数执行之前做的事')

   ret = func(*args,**kwargs)

   print('在被装饰的函数执行之后做的事')

   return ret

   return inner

  @wrapper #holiday = wrapper(holiday)

  def holiday(day):

   '''

   这是一个放假通知

   :param day:

   :return:

   '''

   print('全体放假%s天'%day)

   return '好开心'

  print(holiday.__name__)

  print(holiday.__doc__)

  '''

  结果是inner和None 但我们想要的是打印holiday的字符串格式的函数名和函数的注释这时该怎么办?

  解决方法就是 from functools import wraps

  使用语法是@wraps(被装饰的函数名)

  '''

  输出结果:

  holiday

   这是一个放假通知

   :param day:

   :return:



六、装饰器 —— 装饰原则

  • 1、开放封闭原则

      

1.对原函数的功能扩展是开放的

  为什么要对功能扩展开放呢?

  对于任何一个程序来说,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许后来扩展、添加新功能。

  2.对修改是封闭的

   为什么要对修改封闭呢?

   就像我们刚刚提到的,因为我们写的一个函数,很有可能在其他地方已经被导入使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经正在使用该函数的代码。

  装饰器就完美遵循了这个开放封闭原则。这就是学装饰器的初衷

  



小结:

  • 1、装饰器的固定格式(模板)

      

#格式一

  def timer(func):

   def inner(*args,**kwargs):

   '''执行函数之前要做的'''

   re = func(*args,**kwargs)

   '''执行函数之后要做的'''

   return re

   return inner

  #格式二

  from functools import wraps

  def deco(func):

   @wraps(func) #加在最内层函数正上方

   def wrapper(*args,**kwargs):

   return func(*args,**kwargs)

   return wrapper

推荐学习:python以上就是深入了解Python装饰器函数的详细内容,更多请关注盛行IT软件开发工作室其它相关文章!

  

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: