楔子
前提,我有一段代码(一个函数)。
import time def run_time(): time.sleep(0.1) print('我曾踏足山巅')
需求1:现在,我想计算这段代码的运行时间。
我可以这样做:
import time def run_time(): start_time = time.time() time.sleep(0.1) print('我曾踏足山巅') end_time = time.time() run_t = end_time - start_time print('运行时间为:',run_t) run_time()
此时,需求是可以实现的。
需求2:不想如此麻烦
如果有很多个类似的函数需要计算运行时间,那这种方法就会显得特别繁琐。
我们可以不修改源代码,再定义一个计算时间的函数,将需要被计算时间的函数名作为参数传进去,
直接调用函数进行计算运行时间,就不需要每个函数里面都加入相同代码了。
下面进行升级:
import time def run_time(): time.sleep(0.1) print('我曾踏足山巅') def run_time1(): time.sleep(1) print('也曾堕入低谷') def calculation(f): start_time = time.time() f() end_time = time.time() run_t = end_time - start_time print('运行时间为:', run_t) #直接调用函数进行计算 calculation(run_time) calculation(run_time1)
需求3:我还想要不修改调用方式直接实现时间的计算。
即还是直接调用原函数,但是能同时实现原功能以及时间计算的功能。
由此,我们引入装饰器函数的概念。
python装饰器
装饰器的定义
python装饰器就是用来拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数。
使用python的好处就是不用更改原函数代码的前提下给函数增加新的功能。
装饰器的特点
不修改被装饰函数的调用方式,不修改被装饰函数的源代码。
实例:实现
备注:语法糖
import time def run_time(f): #装饰器函数 def inner(): start_time = time.time() f() end_time = time.time() run_t = end_time - start_time print('运行时间为:', run_t) return inner # func = run_time(func)#不修改函数调用方式,添加新功能 @run_time#语法糖,代替赋值调用,等价于上一行代码 def func(): time.sleep(0.1) print('hello world') func()
可以看出,在不改变原函数调用方式的情况下,也实现了运行时间的计算。
原函数的源码没有改变,调用方式没有改变,并且追加了新的运行时间计算功能。
装饰器的返回值
如果被装饰的参数有返回值。
import time #装饰器必定要是一个闭包函数 def run_time(f): def inner(): start = time.time() func_retrun = f() # func_return = func() 变量接收被装饰函数的返回值 end = time.time() print('被装饰函数运行时间为:',end - start) return func_retrun return inner @run_time #被装饰函数 def func(): time.sleep(0.1) print('hello world') return '这是被装饰函数返回值' # func = run_time(func) #结果:func = inner s = func() print(s)
装饰器的参数
一、位置参数
#带有参数的函数装饰器 def wrapper(f): def inner(a): print('装饰器增加的额外内容:hello world') return f(a)#返回被装饰函数的返回值 # f(a) return inner @wrapper def func(a): print('被装饰函数的参数输入:',a) return '被装饰函数的返回值:was a day' s = func('once before,a little ...') print(s)
二、默认参数
#此装饰器 wrapper 实现增加时间戳功能 import time def wrapper(f): def inner(a,b,c = 'default'):#在这里加默认参数,还有动态参数亦如是 print(time.asctime()) r = f(a,b,c) return r return inner @wrapper def func(a,b,c ): print(a,b,c) return '被修饰函数返回值' s = func(1,2) print(s)
三、动态参数
注:其实下例中的被装饰函数并没有用到参数。不过你可以根据需求自己来进行试验,不再赘述。
# 此装饰器 wrapper 实现增加时间戳功能 import time def wrapper(f): def inner(*args,**kwargs): print(time.asctime()) r = f(*args,**kwargs) return r return inner @wrapper def func2(): print(''' 三更灯火五更鸡, 正是男儿读书时。 黑发不知勤学早, 白首方恨读书迟。''') r1 = '''这首诗深入浅出,自然流畅,富含哲理。核心是“黑发早勤学,白首读书迟”。 从学习的时间这一角度立意,劝勉年轻人不要虚度光阴,要及早努力学习,免得将来后悔。''' return r1 s = func2() print(s)
装饰器的功能和固定结构
装饰器的主要功能
在不改变函数调用的基础上在函数的前、后添加功能。
装饰器的固定结构
def wrapper(f):#装饰器函数,f是被装饰函数 def inner(*args,**kwargs): '''执行函数之前要做的''' r = f(*args,**kwargs) '''执行函数之后要做的''' return r#解释器原则,从上至下,返回值最后才进行输出 return inner @wrapper #之后要使用装饰器函数的时候,直接调用就可以了
pass