好多年一直没学特别明白的知识始终缠绕着我。打算先写简单一点。

装饰器的目的是在不改变函数本身的前提下,为函数增添新的功能。

# 简单的例子

比如,下面是一个简单的函数,用来输出一个字符串 run func1

def func1():
    print("run func1")
    
func1()

如果希望对其进行修改,使其先输出 program start , 再输出 run func1 ,那么就需要对 func1 进行修改,也就是

def func1():
    print("program start")
    print("run func1")
func1()

但是这样修改了函数本身。如果不修改,简单的方式是新定义一个函数,即

def func1():
    print("run func1")
def prog1(func):
    print("program start")
    func()
prog1(func1)

如果我们想要在调用原有函数 func1 的情况下,同时不改变 func1 本身,那么就需要再调用一次。比如:

def func1():
    print("run func1")
def prog1(func):
    print("program start")
    func()
func1 = prog1(func1)
func1()

但是这里会出现报错,因为 prog1 的返回是空值,因此不能作为 func1 被赋予的值。于是需要再嵌套一层包裹函数:

def func1():
    print("run func1")
def prog1(func):
    def warpper():
        print("program start")
        func()
    retturn warpper
func1 = prog1(func1)
func1()

但是这样写 func1 = prog1(func1) 比较难懂,所以就使用了一个语法糖 @ , 变成:

def prog1(func):
    def wrapper():
        print("program start")
        func()
    return wrapper
@prog1
def func1():
    print("run func1")
func1()

嗯,这就是装饰器。

总的来说,如果要写一个装饰器,需要包括两部分:

  1. 装饰器函数,也就是 prog1 , 其包含了需要对被装饰函数所新增的内容。
  2. 被装饰函数,也就是 func1 , 这里需要在其之前写 @prog1 表明该函数使用了装饰器 prog1 .

# References

  • Python 的高阶玩法:装饰器(没人比我讲的更简单易懂了吧) - jasonj333 的文章 - 知乎