学科分类
目录
基础

什么是装饰器

装饰器本质是一个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所示。

image-20200616144731600

图1 执行wrap(test)

② 将wrap(test)的返回值赋给test,此时,test指向inner()函数,如图2所示。

image-20200616144801933

图2 执行test=wrap(test)

到此,我们完成了函数test()的装饰。

(2)调用test()指向的函数。因为test指向的是inner()函数,所以此时,调用test()函数相当于调用inner()函数,输出过程如下:

① 输出print语句“正在验证权限”。

② 调用func指向的函数,输出“test”。

点击此处
隐藏目录