思想:不要重复自己的工作,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 ,函数里面又定义了一个函数,这种特殊的函数,称为闭包