什么是装饰器
装饰器本质是一个Python函数,它可以在不改动其他函数的前提下,对函数的功能进行扩充。通常情况下,装饰器用于下列场景:
(1)引入日志;
(2)函数执行时间统计;
(3)执行函数前预备处理;
(4)执行函数后清理功能;
(5)权限校验;
(6)缓存。
先看一个简单的例子。
def test_one():
print('test_one')
现在有一个需求,希望可以输出函数的执行日志,这时,有人会这么实现:
def test_one():
print('test_one')
print('test_one is running')
test_one()
但是,如果函数test_two()、函数test_three()都有类似的需求,那么现在这样的做法会出现大量重复的代码。为了减少代码重复,我们可以创建一个新的函数专门记录函数执行日志,谁需要记录执行日志,就把谁作为参数传递,示例代码如下:
def print_log(func):
print('函数正在运行中')
func()
def test():
print('test')
print_log(test)
按照上述代码将函数作为参数传递,虽然可以实现功能,但是却破坏了原有代码的逻辑结构。如果要求已经实现的函数,不能修改,只能扩展,即遵守“封闭开放”原则,那么是不允许在函数test内部进行修改的。
装饰器可以满足上述需求。在Python中,装饰器的语法是以@开头,下面,我们写一个简单的装饰器。
def wrap(func):
print('正在装饰')
def inner():
print('正在验证权限')
func()
return inner
@wrap
def test():
print("test")
test()
下面我们来分析一下程序的执行过程。
(1)当程序执行test()时,发现函数test()上面有装饰器@wrap,所以会先执行@wrap。@wrap等价于test=wrap(test),它可以拆分为两步:
① 执行wrap(test),将函数名test作为参数传递给wrap。在调用wrap函数的过程中,首先会执行print语句,输出“正在装饰”,然后会将形参func指向test()函数体,并将inner()函数的引用返回给wrap(test),作为wrap(test)的返回值,具体如图1所示。
图1 执行wrap(test)
② 将wrap(test)的返回值赋给test,此时,test指向inner()函数,如图2所示。
图2 执行test=wrap(test)
到此,我们完成了函数test()的装饰。
(2)调用test()指向的函数。因为test指向的是inner()函数,所以此时,调用test()函数相当于调用inner()函数,输出过程如下:
① 输出print语句“正在验证权限”。
② 调用func指向的函数,输出“test”。