本文目的是由浅入深地介绍python装饰器原理
装饰器(Decorators)是 Python 的一个重要部分
其功能是, 在不修改原函数(类)定义代码的情况下,增加新的功能
为了理解和实现装饰器,我们先引入2个核心操作:
1 必要的2个核心操作
1.1 核心操作1, 函数内部可以定义函数
def hi(name='world'): print(f"hello, {name}") def howdoyoudo(name2=name): print(f"how do you do? {name2}") howdoyoudo() howdoyoudo('world') hi("ytt") # 但是新函数还是存在的。 hi("ycy") # 但是新函数还是存在的。 try: howdoyoudo() except: print("function not found")
在这个例子中,函数hi的形参name,默认为'world'
在函数内部,又定义了另一个函数 howdoyoudo,定义这个函数时,将形参name作为新函数的形参name2的默认值。
因此,在函数内部调用howdoyoudo()时,将以调用hi时的实参为默认值,但也可以给howdoyoudo输入其他参数。
上面的例子运行后输出结果为:
hello, ytt how do you do? ytt how do you do? world hello, ycy how do you do? ycy how do you do? worldfunction not found
这里新定义的howdoyoudo可以称作一个“闭包”。不少关于装饰器的blog都提到了这个概念,但其实没必要给它取一个多专业的名字。我们知道闭包是 函数内的函数 就可以了
1.2 核心操作2 函数可以作为对象被输入输出
1.2.1 核心操作2的前置条件,函数是对象
当我们进行 def 的时候,我们在做什么?
def hi(): print("hi") return "world"
这时,hi函数,打印一个字符串,同时返回一个字符串。
但hi函数本身也是一个对象,一个可以执行的对象。执行的方式是hi()。
这里hi和hi()有本质区别,
hi 代表了这个函数对象本身
hi() 则是运行了函数,得到函数的返回值。
def hi(name='world'): print(f"hello, {name}") return name msg = hi() # 运行函数,返回字符串,因此msg是个字符串 print(msg) hello = hi # 将函数本身赋值给hello,此时hello是另一个函数,即使删除原函数hi,新函数hello也可以正常调用 del hi # 删除原函数hi try: hi() except: print("func hi not found") hello("ycy") # 但是新函数还是存在的。
作为对比,可以想象以下代码
a = 'example' b = a del a
此时也是b存在,可以正常使用。
1.2.2函数作为输入
我们定义2个函数,分别实现自加1, 自乘2,
再定义一个函数double_exec,内容是将某个函数调用2次
在调用double_exec时,可以将函数作为输入传进来
def func1(n): return n+1 def func2(n): return n*2 def double_exec(f,x): return f(f(x)) rst = double_exec(func1, 5) print(rst) rst = double_exec(func2, 3) print(rst)
输出结果就是
7
27
1.2.3 函数作为输出
同样,也可以将函数作为输出
def select_func(i): def func1(n): return n+1 def func2(n): return n*2 func_list = [func1, func2] return func_list[i] func = select_func(0) # 第1个函数 print(func(5)) func = select_func(1) # 第2个函数 print(func(5))
输出结果为
6
10
2 尝试构造装饰器
有了以上两个核心操作,我们可以尝试构造装饰器了。
装饰器的目的: 在不修改原函数(类)定义代码的情况下,增加新的功能
试想一下,现在有一个原函数
def original_function: print("this is original function")
在不修改原函数定义代码的情况下,如果想进行函数内容的添加,可以将这个函数作为一个整体,添加到这样的包裹中:
def my_decorator(f): def wrap_func(): print(f"before c