python中装饰器进化史

思想:不要重复自己的工作,Don't repeat yourself
目的:我有一个函数countdown,现在想统计一下这个函数的运行时长。改装之后呢,计时功能有了,运行时和改装前一样,改装前运行:countdown(100000000)

第一种写法,初级写法:
 1 def countdown(n):
 2     while n>0:
 3         n-=1
 4 
 5 def wrapper(func,*args,**kwargs):
 6     start = time.time()
 7     result = func(*args, **kwargs)
 8     end = time.time()
 9     print(func.__name__, end - start)
10     return result
11 
12 wrapper(countdown,100000000)
使用之前:countdown(100000000)
使用之后:wrapper(countdown,100000000)
这样,功能增加增加后,函数运行的方式改变了,意思不清楚,别人看你的代码,容易产生误会,代码可读性下降!

第二种,过度写法:
 1 def timethis(func):
 2     # @wraps(func)
 3     def wrapper(*args,**kwargs):
 4         start=time.time()
 5         result=func(*args,**kwargs)
 6         end=time.time()
 7         print(func.__name__,end-start)
 8         return result
 9     return wrapper
10 
11 def countdown(n):
12     while n>0:
13         n-=1
14 
15 # 1,对函数包装,装饰器本身就是一个函数
16 countdown = timethis(countdown)
17 # 2,这一步才执行函数
18 countdown(100000000)
# 使用之前:countdown(100000000)
# 使用之后:countdown(100000000)
总结:第二种写法,已经实现了要求的,符合要求,加了一行 countdown = timethis(countdown),哪个函数需要计时功能,用这个timethis包装一下就行了,但是有没有更优雅简洁的写法呢?

第三种,究极写法:

 1 def timethis(func):
 2     # @wraps(func)
 3     def wrapper(*args,**kwargs):
 4         start=time.time()
 5         result=func(*args,**kwargs)
 6         end=time.time()
 7         print(func.__name__,end-start)
 8         return result
 9     return wrapper
10 
11 @timethis
12 def countdown(n):
13     while n>0:
14         n-=1
15 
16 countdown(100000000)
# 使用之前:countdown(100000000)
# 使用之后:countdown(100000000)
总结:这种写法和第二种写法,@timethis和countdown = timethis(countdown)功能是一样的,但是很显然@timethis更简洁,@是官方提供的友好的“语法糖”,也是为了能把装饰器表达的意思更清晰
而实现装饰器的这个函数,timethis ,函数里面又定义了一个函数,这种特殊的函数,称为闭包
posted @ 2021-05-26 21:06  年轻人——001  阅读(46)  评论(0编辑  收藏  举报