说一说那些我也不太懂的 Python 装饰器

来源:互联网 发布:如何获取股票数据 编辑:程序博客网 时间:2024/04/28 11:56

什么是装饰器?

简单点解释:装饰器就是一个可调用对象,其参数是被其装饰的可调用对象

是不是感觉有点绕?稍微具体一点解释:

因为函数在 Python 中是一等公民,所以一个函数可以接收另一个函数作为参数并返回一个新的函数,这样的一个函数就被称之为装饰器(这里先不讨论装饰类的情况)。

举个栗子:

#! /usr/bin/env python# -*- coding: utf-8 -*-# 定义一个装饰器def add_prefix(func):    def inner_func(args):        return '/home/xieyanke/' + args    return inner_func@add_prefixdef test(path):    return pathif __name__ == '__main__':    print(test('factory'))    # 输出结果为:/home/xieyanke/factory

装饰器何时执行?

装饰器在 Python 模块导入时便执行了,所以装饰器在所有被装饰函数之前执行,也优先于被导入模块内所有可执行对象执行。

示例:my_decorator.py

#! /usr/bin/env python# -*- coding: utf-8 -*-def dec(func):    print('my_decorator running...')    return func

示例:main.py

#! /usr/bin/env python# -*- coding: utf-8 -*-from my_decorator import dec@decdef main1():    print('func: main1 running')def main2():    print('func: main2 running')if __name__ == '__main__':    main2()    main1()# 执行结果:# my_decorator running...# func: main2 running# func: main1 running

多个装饰器的执行顺序是什么?

假如一个函数被多个装饰器装饰,那么这些装饰器的执行顺序为自底向上执行

示例:main.py

#! /usr/bin/env python# -*- coding: utf-8 -*-def dec1(func):    print("dec1 running...")    return funcdef dec2(func):    print("dec2 running...")    return func@dec1@dec2def main():    print('func: main running')if __name__ == '__main__':    main()## 执行结果:# dec2 running...# dec1 running...# func: main1 running# 从结果可以看出多个装饰器的执行顺序为自底向上执行

装饰器如何接收参数?

如果我们使用一些其他框架例如:Flask ,经常发现框架中的装饰器是可以接收参数的。我们如何自定义一个可以接收普通参数的装饰器呢?

答案是:还真不能定义一个可以接收普通参数的装饰器。那么别人的框架是怎么实现的呢?其实这里面涉及到了闭包与自由变量的语法糖(关于闭包与自由变量后期会单独写一篇详细介绍,这里先带过了),那么要实现一个看着像可以接收普通参数的装饰器,需要先定义一个函数接收普通参数,然后返回这个函数内部实现的装饰器,这样就实现了一个看似可以接收普通参数的装饰器。

示例:main.py

#! /usr/bin/env python# -*- coding: utf-8 -*-def dec1(arg):    def dec(func):        print("dec1 receive args: " + arg)        return func    return dec@dec1('arg_demo')def main1():    print('func: main1 running')if __name__ == '__main__':    main1()

最后说一说为什么要使用装饰器?

  1. 想用装饰器的内容替换被装饰函数的内容
  2. 想用装饰器的内容改进被装饰函数的内容
  3. 想把被装饰函数注册到某处

1. 想在被装饰函数的执行前后做一些操作

  • 交流可以加 QQ 群:397234385
  • 或者 QQ 扫码入群:

qq群.jpg

原创粉丝点击