Python有一个强大的特性—装饰器,它可以给已经实现的代码块(函数)包裹上自己想要添加的功能,而不用考虑函数内是怎么实现的
阐述装饰器之前可以先了解一下Python另一个特性—闭包
闭包
闭包是在函数内再定义一个函数,并且提供了子函数需要的变量,这样可以把子函数与其用到的变量叫做闭包
def line_para(a, b):
def line(x):
return a * x + b
return line
如上代码,定义一个line_para函数,其返回的是子函数line,line_para内定义函数line,这样实现了一个闭包,可以通过传入不同的参数a, b,来获得不同的数学上的二元一次函数
line1 = line_para(2, 4)
line2 = line_para(3, 6)
print(line1(10))
print(line2(10))
# 24
# 36
闭包可以根据需要,创建不同的,又具有一定相似度的函数。这种思想也是装饰器的思想
装饰器
上文有描述,装饰器可以给以实现的函数添加功能。这是一种优雅的实现方法,符合敏捷开发的封闭开放原则。
封闭开放原则:已经实现的功能代码不允许被修改,而是将其扩展
import time
def my_func(func):
def inner(a)
print(time.time())
func(a)
print(time.time())
return inner
@my_func
def other_func(a):
pass
other_func(123)
如上my_func就是实现一个简单的装饰器,假设函数other_func是从别人那儿拿来的,我们并不知道它是怎么实现的,只知道想要给他添加运行开始时间和结束时间。我们可以这样来理解它:
- 符号"@"标识程序会使用一个装饰器my_func,
- 程序将函数other_func作为参数传入装饰器my_func,之后又将返回值赋值给变量other_func
other_func = my_func(other_fun)
- 然后将原函数other_function的参数传给装饰器my_function返回的对象
my_func(other_func)(a)
-
这样再执行other_func就相当于执行装饰器my_func返回的对象inner函数,执行inner函数就会先打印一下时间戳,然后执行func函数,此时局部变量func指向的是原函数other_func的函数体,也就是执行原函数other_func,最后再打印一下时间戳,这样就实现了一个给原函数other_func添加显示开始、结束时间功能的装饰器
类装饰器
上面是用函数的方式实现装饰器,其实装饰器还可以通过类来实现
import time
class my_func:
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
print(time.time())
self._func(*args, **kwargs)
print(time.time())
@my_func
def other_func(a)
pass
other_func(123)
其运行的原理其实和函数实现方法差不多:
- 符号"@"标识程序会使用一个装饰器my_function
- 将函数other_func传给类my_func的实例,之后又将其返回值赋值给other_function
other_func = my_func(other_func)
- 这样运行other_func就是运行类my_func的实例,参数就会被传入__call__方法中,执行call方法就可以实现打印开始时间戳,执行原函数other_func,打印结束时间戳
装饰器很强大,在Python中很多地方都用到它,比如Flask就是通过其实现了很多功能,有待我以后慢慢描述~~