python笔记35-装饰器
前言
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。 很多python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。
计算函数运行时间
假设你写了几个函数,有一天领导心血来潮说,你把每个函数的运行时长(结束时间-开始时间)统计下,作为一个python实习生的你可能会这样写
原始函数
import timedef func_a():
print("hello")
time.sleep(0.5)def func_b():
print("world")
time.sleep(0.8)if __name__ == '__main__':
func_a()
func_b()
添加运行时长
作为一个实习生的你,可能想到的解决办法如下
import timedef 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 timedef 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()
运行结果
hello
运行时长:0.5001 秒
world
运行时长:0.8001 秒
函数带参数装饰器
上面的runtime就是一个简单的装饰器模型了,但并不强壮,如果函数里面带有参数,那就不管用了,并且函数的参数是不固定的,这时候就需要用到*args
,**kwargs
两兄弟了
import timedef 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__
方法,那么实例对象也将成为一个可调用对象
import timeclass runtime(object):
def __init__(self, func):
self.func = funcdef __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 timedef 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 timeclass runtime(object):
def __init__(self, slowly=1):
self.slowly = slowlydef __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")
使用场景
用哪些地方需要使用装饰器呢?
- 如果你用过locust,设置权重会用到
@task(1)
, - 如果你用过pytest框架,使用fixture功能的时候经常会用到
@pytest.fixture(scope="function")
- allure里面可以添加测试步骤
@allure.step('修改购物车')
- 被大量使用于Flask和Django web框架中,检查是否被授权去使用一个web应用的端点(endpoint)。如
@login_required
- 也可以自己写个装饰器添加日志
- Struts2 S2-052 RCE简单测试
- javaScript实现归并排序
- js粘贴事件paste简单解析及遇到的坑
- 学习zepto.js(对象方法)[6]
- Javascript 装饰器极速指南
- daterangepicker日历插件使用参数注意问题
- 学习zepto.js(对象方法)[5]
- js 停止事件冒泡 阻止浏览器的默认行为
- vue-cli生成的项目配置开发和生产环境不同的接口
- 【52ABP实战教程】0.1-- Devops如何用VSTS持续集成到Github仓库!
- 学习zepto.js(对象方法)[4]
- 事件绑定的几种常见方式
- vue的iview列表table render函数设置DOM属性值的方法
- js焦点轮播图
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PC人脸识别登录,出乎意料的简单
- TensorLayer学习之简介与安装
- JVM系列之:String.intern的性能
- 神经网络架构搜索——可微分搜索(DARTS)
- 神经网络架构搜索——可微分搜索(P-DARTS)
- 神经网络架构搜索——可微分搜索(PC-DARTS)
- 反编译小程序记录
- 使用Selenium WebDriver,Python和Chrome编写您的第一个Web测试
- 神经网络架构搜索——可微分搜索(SGAS)
- 神经网络架构搜索——可微分搜索(Fair-DARTS)
- 一帧图像的Android之旅 :应用的首个绘制请求
- Mac免密码登录linux服务器
- 目标检测算法YOLO-V2详解
- 神经网络架构搜索——可微分搜索(Noisy DARTS)
- 教你使用 Jacoco 统计服务端代码覆盖率