1 引言
ASP站长网装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨——人生苦短,我用Python。
 
2 初步理解装饰器
2.1 什么是装饰器
在解释什么是装饰器之前,我们有必要回顾一下Python中的一些思想和概念。我们都知道,Python是一门面向对象的语言,Python基本思想就是一些皆对象,数据类型是对象、类是对象、类实例也是对象……对于接下来我们要说的装饰器而言,最重要的是,函数也是对象!
 
你没看错,函数也和数据类型等概念一样,都是对象,那么既然数据类型可以进行赋值操作,那么函数是不是也可以赋值呢?当然可以!
 
def do_something():
    print('完成一些功能')
 
if __name__ == '__main__':
    do = do_something
    do()
输出:
 
完成一些功能
 
看,原本我们定义的函数名是do_something,但我们把函数赋值给do后,也可以通过do()调用函数。不仅如此,函数当做参数传递给其他函数:
 
def do_something():
    print('正在完成功能')
 
def func(f):
    f()
 
if __name__ == '__main__':
    func(do_something)
输出:
 
完成一些功能
 
正是因为Python中函数既可以赋值给其他变量名,也可以当做参数参数进其他函数,所以,上面的代码没有任何问题。
 
当然,毕竟被称呼为函数,有别有变量之类的概念,所以它也有自己的特性,例如在函数内部,还可以定义函数,甚至作为返回值返回:
 
def func():
    def inner_func():
        print('我是內部函数')
    return inner_func
 
if __name__ == '__main__':
    fun1 = func()
    fun1()
输出结果:
 
我是內部函数
 
我们来总结一下函数的这几个特性:
 
可以赋值给其他变量;
 
可以作为参数传递给其他函数;
 
可以在内部定义一个函数;
 
可以当做返回值返回。
 
不要疑惑我为什么要着重说明Python中函数的这几个特性,因为装饰器中正是这几个特性为基石。为什么这么说呢?从本质上来说,装饰器就是一个函数,它也具有我们上面说到的4个特性,而且充分利用了这4个特性。装饰器接受一个普通函数作为参数,并在内部定义了一个函数,在这个内部函数中实现了一些功能,并调用了传递进来的函数,最后将内部函数作为返回值返回。如果一个函数把这个步骤全走了一遍,我们就可以认为,这个函数是一个装饰器函数,或者说装饰器。
 
我们来动手写一个装饰器:
 
def func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        f()
        print('{}函数结束运行……'.format(f.__name__))
    return inner_func
 
def do_something():
    print('正在完成功能')
 
if __name__ == '__main__':
    do_something = func(do_something)
    do_something()
输出结果:
 
do_something函数开始运行……
 
正在完成功能
 
do_something函数结束运行……
 
在上面代码中,我们将do_something方法作为参数传递给func方法,在func方法内部我们定义了一个inner_func方法,并在这个方法中添加了函数开始执行和结束执行的提示,在func方法最后,我们将inner_func作为参数返回,更加值得一说的是,我们重新将func函数的返回值赋给了do_something,所以,最后一行我们再次调用的do_something方法已经不再是最初的do_something函数,而是func方法内定义的inner_func函数,所以最后执行do_something函数时,会有函数开始执行和结束执行的提示功能,而后面再调用do_something函数时,也都直接使用do_something()。
 
正如你所预料,func函数就是一个装饰器,捋一捋你会发现,func函数把我们上面说过的所有特性、步骤全实现了。
 
如果你在别处见过Python装饰器的使用,你可能会疑惑,我们实现的func装饰器跟你见过的装饰器不都一样,因为在实际应用中,装饰器大多是与“@”符号结合起来使用。其实“@”符号所实现的功能就是 do_something = func(do_something)这行代码的功能。来,我们尝试一下使用“@”:
 
def func(f):
    def inner_func():
        print('{}函数开始运行……'.format(f.__name__))
        f()
        print('{}函数结束运行……'.format(f.__name__))
    return inner_func
 
@func
def do_something():
    print('正在完成功能')
 
if __name__ == '__main__':
    do_something()
输出结果:
 
do_something函数开始运行……
 
正在完成功能
 
do_something函数结束运行……
 
之前我们知道,func函数就是一个装饰器,所以使用“@”符号时,我们只需要在被装饰的函数前面加上“@func”就表示该函数被func装饰器装饰,在需要处直接调用do_something函数即可。

dawei

【声明】:九江站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。