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 ,函数里面又定义了一个函数,这种特殊的函数,称为闭包
全世界的程序员们联合起来吧!