美文网首页Python 指南码农的世界
说一说那些我也不太懂的 Python 装饰器

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

作者: 谢烟客 | 来源:发表于2017-09-05 15:49 被阅读68次

    什么是装饰器?

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

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

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

    举个栗子:

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    # 定义一个装饰器
    def add_prefix(func):
        def inner_func(args):
            return '/home/xieyanke/' + args
        return inner_func
    
    @add_prefix
    def test(path):
        return path
    
    if __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
    
    @dec
    def 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 func
    
    def dec2(func):
        print("dec2 running...")
        return func
    
    @dec1
    @dec2
    def main():
        print('func: main running')
    
    if __name__ == '__main__':
        main()
    
    ## 执行结果:
    # dec2 running...
    # dec1 running...
    # func: main 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. 想把被装饰函数注册到某处
    4. 想在被装饰函数的执行前后做一些操作

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

    相关文章

      网友评论

        本文标题:说一说那些我也不太懂的 Python 装饰器

        本文链接:https://www.haomeiwen.com/subject/zzcicxtx.html