【基础篇】细说Python装饰器.md

2022/6/13 Python小技巧

大家好~我是米洛

我正在从0到1打造一个开源的接口测试平台, 也在编写与之配套的一套完整教程,希望大家能够多多支持。

欢迎关注我的公众号米洛的测开日记,获取最新文章教程!

# 装饰器

装饰器,很多人都会被这个名词震慑住,那它究竟是干嘛的,怎么使用原理是什么呢?

先聊聊装饰器,装饰器我个人理解是Python的一种语法糖,它常常用于方法调用之前/之后做的一些处理操作。

# 举个栗子🌰

  • 计算方法执行时间

    如果我要计算一个方法的执行时间,那我可以在方法调用之前记录下时间,执行完成后用当前时间 - 之前记录的时间,这样就能拿到方法的执行时间

  • 日志、操作记录

    我这个方法我想知道什么时候被调用了,有谁调用了,我都要记到小本本上,我们就可以用装饰器来帮我们做这个事情。

  • 判断用户是否登录

    我们编写web系统常常会判断用户登录与否,没登录就不调用接口方法了,直接给他一个需要登录的提示,或者将用户跳转回登录页。---

    所以呢,装饰器一般是在方法执行之前执行之后帮忙做一些工作。

# 先来看一个最简单的装饰器

我们想在方法执行之前打印一些话,执行之后也打印一些话。

def simple(func):
    def wrapper():
        print("开始了")
        func()
        print("结束了")

    return wrapper


@simple
def func():
    print("方法正在执行中")
    
if __name__ == "__main__":
    func()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

先看下结果:

# 解释

定义了一个simple方法,方法里面套了一层wrapper方法,wrapper里面执行了func(),并在func执行之前/之后都输出了对应的语句,最后返回了wrapper。

在对应的func方法下面加上@simple,代表simple成为了func的一个装饰器。@这个是装饰器的固定写法,大家不要惊慌,我们来拆解一下:

  1. 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)()
1
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()
1
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

执行结果,可以看到参数正常传递了

可以看到,区别就是wrapper那儿加上了*args和**kwargs有这2个参数在,就可以囊括包裹方法的所有参数了

之所以这么写,是为了让装饰器能适配更多方法,其实我这么写,只对我一个方法生效,也是没问题的,但是通用性就很差。

所以这就解释了,为啥一般装饰器都是*args, **kwargs

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

# 更多装饰器

相信大家一下子也不能轻易消化,其实装饰器还有其他变种,比如类装饰器,又或者装饰类的装饰器。原来基本都类似。大家掌握了这里面的内容以后,就可以去了解下更多装饰器的用法了,下一篇教大家怎么用装饰器处理异步方法

觉得有用的话🔥记得点个关注❤️‍ 哦~

# 进阶的小作业

我想要一个循环执行N次方法的装饰器,命名为loop,如果@loop形式,则不进行循环,如果是@loop(5),则要循环方法5次,你可以试试吗?

@loop
def func1():
    pass
    
@loop(5)
def func2():
    pass
1
2
3
4
5
6
7