python装饰器本质上就是一个函数,它可让其余函数在不须要作任何代码变更的前提下增长额外的功能,装饰器的返回值也是一个函数对象。
不少python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。python
假设你写了几个函数,有一天领导心血来潮说,你把每一个函数的运行时长(结束时间-开始时间)统计下,做为一个python实习生的你可能会这样写web
import time def func_a(): print("hello") time.sleep(0.5) def func_b(): print("world") time.sleep(0.8) if __name__ == '__main__': func_a() func_b()
做为一个实习生的你,可能想到的解决办法以下app
import time def func_a(): start = time.time() print("hello") time.sleep(0.5) end = time.time() print("运行时长:%.4f 秒" % (end-start)) def func_b(): start = time.time() print("world") time.sleep(0.8) end = time.time() print("运行时长:%.4f 秒" % (end-start)) if __name__ == '__main__': func_a() func_b()
运行结果:框架
hello 运行时长:0.5009 秒 world 运行时长:0.8008 秒
上面的代码虽然知足了领导的要求,可是若是你写的函数不少的话,每一个函数都这样去添加,会显得代码很臃肿,有不少重复代码。
有一天你边上的一个python老司机看了下你的代码,给你指了条路:装饰器函数
装饰器能够写成函数式装饰器,也能够写成一个类装饰器,先从简单的函数装饰器开始学习。
python装饰器本质上就是一个函数,它可让其余函数在不须要作任何代码变更的前提下增长额外的功能,装饰器的返回值也是一个函数对象。学习
runtime函数就是一个装饰器了,它对原函数作了包装并返回了另一个函数,额外添加了一些功能。在函数上方使用@语法糖就能够调用这个装饰器了测试
import time def runtime(func): def wrapper(): start = time.time() f = func() # 原函数 end = time.time() print("运行时长:%.4f 秒" % (end-start)) return f return wrapper @runtime def func_a(): print("hello") time.sleep(0.5) @runtime def func_b(): print("world") time.sleep(0.8) if __name__ == '__main__': func_a() func_b()
运行结果ui
hello 运行时长:0.5001 秒 world 运行时长:0.8001 秒
上面的runtime就是一个简单的装饰器模型了,但并不强壮,若是函数里面带有参数,那就无论用了,而且函数的参数是不固定的,这时候就须要用到*args
,**kwargs
两兄弟了日志
import time def runtime(func): def wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函数 end = time.time() print("运行时长:%.4f 秒" % (end-start)) return f return wrapper @runtime def func_a(a): print("hello"+a) time.sleep(0.5) @runtime def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")
关于__call__
方法,不得不先提到一个概念,就是可调用对象(callable),咱们平时自定义的函数、内置函数和类都属于可调用对象,
但凡是能够把一对括号()应用到某个对象身上均可称之为可调用对象,判断对象是否为可调用对象能够用函数 callable。
若是在类中实现了__call__
方法,那么实例对象也将成为一个可调用对象code
import time class runtime(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): start = time.time() f = self.func(*args, **kwargs) # 原函数 end = time.time() print("运行时长:%.4f 秒" % (end-start)) return f @runtime def func_a(a): print("hello"+a) time.sleep(0.5) @runtime def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")
快到年末了,领导说运行的速度先不要太快了,让客户先加钱,而后再以正常的速度显示,那么如今的需求是让每一个函数的运行时间加50%,该如何实现呢?
这就到了装饰器的高级语法,装饰器也须要带上参数了
import time def runtime(slowly=1): def wrapper(func): def inner_wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函数 end = time.time() t = end-start time.sleep((slowly-1)*t) # 延迟效果 new_end = time.time() print("运行时长:%.4f 秒" % (new_end-start)) return f return inner_wrapper return wrapper @runtime(1.5) def func_a(a): print("hello"+a) time.sleep(0.5) @runtime(1.5) def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")
import time class runtime(object): def __init__(self, slowly=1): self.slowly = slowly def __call__(self, func): def wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函数 end = time.time() t = end-start time.sleep((self.slowly-1)*t) # 延迟效果 new_end = time.time() print("运行时长:%.4f 秒" % (new_end-start)) return f return wrapper @runtime(1.5) def func_a(a): print("hello"+a) time.sleep(0.5) @runtime(1.5) def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")
用哪些地方须要使用装饰器呢?
@task(1)
,@pytest.fixture(scope="function")
@allure.step('修改购物车')
@login_required
python自动化交流 QQ群:779429633