最近在看python的高级教程,被装饰器这个概念难住了,查了许多相关的资料后,对装饰器有了进一步的了解。 装饰器本质上是一个的函数,一个比较特殊的函数,是一个参数是函数,返回值也是函数的函数。 装饰器的作用是在不改变被装饰函数的前提下,用内部函数(FuncHandler )对被装饰函数进行处理,常用于对一个函数的安全性、性能等运行情况进行检测。
一、基础的装饰器函数
1.装饰器基础
def decorator(func):
def funcHandler():
func()
return funcHandler
@decorator
def test():
pass
上面代码中的decorator 可以对test() 函数相应的自定义处理(Do somthing…)。下面通过print 语句模拟函数的执行过程。
def decorator(func):
print("I am decorator!")
def funcHandler():
print("I am funcHandler!")
func()
return
return funcHandler
@decorator
def decoratedFunc():
print("I am decoratedFunc!")
if __name__ == '__main__':
mainFunc = decoratedFunc
mainFunc()
输出
I am decorator!
I am funcHandler!
I am decoratedFunc!
根据执行结果可以知道,被装饰的函数(decoratedFunc )作为实际参数传入decorator(func) 中,返回funcHandler 函数,执行decoratedFunc() 即执行decorator() 整体。
2.装饰器示例
根据装饰器的性质,可以写一个用于计算函数运行时间的简单的装饰器Timeit 。代码如下,
import time
def Timeit(func):
def handeler():
print("开始测试...")
start = time.time()
func()
return time.time() - start
return handeler
@Timeit
def testFunc():
time.sleep(2)
if __name__ == '__main__':
Result = testFunc()
print(f"运行时间为:{Result} s")
输出
开始测试...
运行时间为:2.005072832107544 s
不使用"@",代码等价于
import time
def Timeit(func):
def handeler():
print("开始测试...")
start = time.time()
func()
return time.time() - start
return handeler
def decoratedFunc():
time.sleep(2)
if __name__ == '__main__':
func = Timeit(decoratedFunc)
Result = func()
print(f"运行时间为:{Result} s")
二、带参数的装饰器
1.增加测试次数
? 在上面函数计时器的基础上,想要增加测试次数(比如说测试100次,1000次以增加结果的可靠性),可以给装饰器增加参数。此时需要给原有的装饰器再“套一层”,以下面的函数计时装饰器为例,
import time
def Timeits(times=10):
def decorator(func):
def handler():
totalTime = 0
print("开始测试...")
for i in range(times):
start = time.time()
func()
result = time.time() - start
totalTime += result
return totalTime/times
return handler
return decorator
@Timeits(100)
def decoratedFuncs():
time.sleep(1)
if __name__ == '__main__':
Result = decoratedFuncs()
print(Result)
输出:
开始测试...
1.005906867980957
带参数的装饰器,是在基础装饰器的基础上再“套一层”用于传入参数,传入参数后,实际的装饰器是再近一层的函数,如本例中的decorator(func) 函数。
2.计时装饰器终极版
除了设置测试次数外,还可以以可变参数的形式为被装饰函数传入参数,以增加计时器的普适性。示例代码如下
import time
def Timeit(number):
def decorator(func):
def handler():
totalTime = 0
print("开始测试...")
for i in range(number):
start = time.time()
func()
result = time.time() - start
totalTime += result
return totalTime / number
return handler
return decorator
def FinalTimeit(testTimes, func, **kwargs):
@Timeit(testTimes)
def decoratedFunc():
return func(**kwargs)
result = decoratedFunc()
return result
if __name__ == '__main__':
def mainFunc(number):
time.sleep(number)
sleepTime = 1
Start = time.time()
Result = FinalTimeit(testTimes=10, func=mainFunc, number=sleepTime)
print(f"被测函数的平均单次运行耗时{Result}s")
print(f"测试总共耗时{time.time()-Start}s")
输出
开始测试...
函数运行平均耗时1.0068019151687622s
测试总共耗时10.068019151687622s
修改后,直接调用FinalTimeit() 函数,传入测试次数(testTimes ),测试函数(func ),和测试函数的参数(如上面的number=sleepTime ),即可返回函数的平均单次运行时间
|