【基础篇】细说Python装饰器.md
大家好~我是
米洛!
我正在从0到1打造一个开源的接口测试平台, 也在编写与之配套的一套完整教程,希望大家能够多多支持。
欢迎关注我的公众号米洛的测开日记,获取最新文章教程!
# 装饰器
装饰器,很多人都会被这个名词震慑住,那它究竟是干嘛的,怎么使用,原理是什么呢?
先聊聊装饰器,装饰器我个人理解是Python的一种语法糖,它常常用于方法调用之前/之后做的一些处理操作。
# 举个栗子🌰
计算方法执行时间
如果我要计算一个方法的执行时间,那我可以在方法调用之前记录下时间,执行完成后用
当前时间-之前记录的时间,这样就能拿到方法的执行时间。日志、操作记录
我这个方法我想知道什么时候被调用了,有谁调用了,我都要记到
小本本上,我们就可以用装饰器来帮我们做这个事情。判断用户是否登录
我们编写web系统常常会判断用户登录与否,没登录就不调用接口方法了,直接给他一个
需要登录的提示,或者将用户跳转回登录页。---所以呢,装饰器一般是在方法
执行之前,执行之后帮忙做一些工作。
# 先来看一个最简单的装饰器
我们想在方法执行之前打印一些话,执行之后也打印一些话。
def simple(func):
def wrapper():
print("开始了")
func()
print("结束了")
return wrapper
@simple
def func():
print("方法正在执行中")
if __name__ == "__main__":
func()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
先看下结果:

# 解释
定义了一个simple方法,方法里面套了一层wrapper方法,wrapper里面执行了func(),并在func执行之前/之后都输出了对应的语句,最后返回了wrapper。
在对应的func方法下面加上@simple,代表simple成为了func的一个装饰器。@这个是装饰器的固定写法,大家不要惊慌,我们来拆解一下:
- func挂载了@simple,其实这一步等于:
simple(func)(),不信我们去掉@simple,换成simple(func)试试。
def simple(func):
def wrapper():
print("开始了")
func()
print("结束了")
return wrapper
def func():
print("方法正在执行中")
if __name__ == "__main__":
simple(func)()
2
3
4
5
6
7
8
9
10
11
12
13
14
15

simple(func)()我们进一步进行拆分,simple(func)这个返回了一个wrapper,而wrapper还是一个方法!(看simple里面的def wrapper)
所以我们拆分一下:
f = simple(func)
f()
2
simple(func)返回了一个f方法,f()则执行了返回的f方法,所以合并到一起就是simple(func)(),这样拆出来就更好理解了。
所以装饰器的本质就是一个function而已,只不过@的写法会便捷很多。不要再认为装饰器是什么很高深的写法了,其实理解下来就是个套娃儿的操作。
# 带参数的装饰器
关于带参数的装饰器,其实原理也一样。
def simple(func):
def wrapper(*args, **kwargs):
print("开始了")
func(*args, **kwargs)
print("结束了")
return wrapper
@simple
def func(a, b, key="lihai"):
print(a, b, key)
print("方法正在执行中")
if __name__ == "__main__":
func(2, 4)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

可以看到,区别就是wrapper那儿加上了*args和**kwargs,有这2个参数在,就可以囊括包裹方法的所有参数了。
之所以这么写,是为了让装饰器能适配更多方法,其实我这么写,只对我一个方法生效,也是没问题的,但是通用性就很差。

遇到参数不是a,b,key的,直接GG,装饰器无法继续使用。

# 更多装饰器
相信大家一下子也不能轻易消化,其实装饰器还有其他变种,比如类装饰器,又或者装饰类的装饰器。原来基本都类似。大家掌握了这里面的内容以后,就可以去了解下更多装饰器的用法了,下一篇教大家怎么用装饰器处理异步方法。
觉得有用的话🔥记得点个关注❤️ 哦~
# 进阶的小作业
我想要一个循环执行N次方法的装饰器,命名为loop,如果@loop形式,则不进行循环,如果是@loop(5),则要循环方法5次,你可以试试吗?
@loop
def func1():
pass
@loop(5)
def func2():
pass
2
3
4
5
6
7

v1.5.1