python笔记35-装饰器
前言
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。
很多python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。
计算函数运行时间
假设你写了几个函数,有一天领导心血来潮说,你把每个函数的运行时长(结束时间-开始时间)统计下,作为一个python实习生的你可能会这样写
原始函数
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()
添加运行时长
作为一个实习生的你,可能想到的解决办法如下
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()
运行结果
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__方法,那么实例对象也将成为一个可调用对象
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")
使用场景
用哪些地方需要使用装饰器呢?
- 如果你用过locust,设置权重会用到
@task(1), - 如果你用过pytest框架,使用fixture功能的时候经常会用到
@pytest.fixture(scope="function") - allure里面可以添加测试步骤
@allure.step('修改购物车') - 被大量使用于Flask和Django web框架中,检查是否被授权去使用一个web应用的端点(endpoint)。如
@login_required - 也可以自己写个装饰器添加日志
python自动化交流 QQ群:779429633
python笔记35-装饰器的更多相关文章
- python笔记 - day4-之装饰器
python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...
- Python笔记:装饰器
装饰器 1.特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能: 2.使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰 ...
- 20.python笔记之装饰器
装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- Python学习笔记:装饰器
Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...
- Python函数06/装饰器
Python函数06/装饰器 目录 Python函数06/装饰器 内容大纲 1.装饰器 1.1 开放封闭原则 1.2 装饰器 2.今日练习 内容大纲 1.装饰器 1.装饰器 1.1 开放封闭原则 扩展 ...
- python高级之装饰器
python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...
- [python基础]关于装饰器
在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...
- Python深入05 装饰器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...
- Day04 - Python 迭代器、装饰器、软件开发规范
1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...
随机推荐
- makefile那些事儿
一.好处 自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案. makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端m ...
- vue做页面按钮权限--分析
import * as types from '../mutation-types' const state = { btnCode: getBtnCode(), } const mutations ...
- SpokenEnglish01_ When's it due?
1 Pronunciation and Intonation When's it due? 解析:When’s it due? 2 Key Points 2.1 Due adj: 到期的,截止的 It ...
- mysql8.0 caching_sha2_password的坑
先来解释一下为什么会报这个错,在mysql8之前的版本使用的密码加密规则是mysql_native_password,但是在mysql8则是caching_sha2_password. 解决方案有很多 ...
- Angular 修改路由策略,改为使用hash路由,即带#号URL
修改app.module.ts如下
- Linux学习、Mongodb部署 踩到的坑学习
一.安装Centos 7虚拟机系统 1.系统安装 下载阿里云的镜像,下载后安装,默认全程图形界面:虚拟机使用Win10自带的Hyper:碰到的坑记录下 1.在Hyper加载镜像启动的时候,提示“虚拟机 ...
- Spring boot + mybatis + mysql代码生成器
引入依赖: 在pom文件最下边: <build> <plugins> <!--逆向工程--> <plugin> <groupId>org.m ...
- redis常用命令及持久化机制
redis 常用命令 查找redis服务文件 find / -name redis-server 查找配置文件 find / -name redis.conf 启动服务时候,要指定配置文件 启动r ...
- 【转帖】极简Docker和Kubernetes发展史
极简Docker和Kubernetes发展史 https://www.cnblogs.com/chenqionghe/p/11454248.html 2013年 Docker项目开源 2013年,以A ...
- updatetable 违反并发性: UpdateCommand 影响了预期 1 条记录中的 0 条造成问题一种原因
数据库 表A ID UserName DeptID DeptName 1 张三 1 技术部 表B ID DeptName 1 市场部 当使 ...