Py进阶|装饰器

作者: 凡有言说 | 来源:发表于2019-12-31 17:04 被阅读0次

    函数装饰器是函数替换的过程——被装饰的函数被替换成另一个东西。

    # 带一个参数的函数,可作为装饰器函数
    def foo (x):
        print('foo')
    
    @foo
    #使用 @foo装饰 bar函数,bar函数是被装饰的函数
    def bar ():
        print('bar')
    
    print('------------')
    print(bar)
    
    foo
    ------------
    None
    

    以上涉及到两个函数:

    • 装饰器函数,用于修饰其他函数的东西,用@标识。理论上来说,任意一个带一个形参的函数都可以作为装饰器函数。
    • 被装饰函数,被装饰器修饰的函数。

    上面的程序中,使用foo()函数装饰bar()函数。

    我们来分析一下输出结果

    foo
    ------------
    None
    

    foo说明foo()函数被调用了,而且在print('------------')
    print(bar)的结果是None,难道是bar()函数变成了None?

    其实是被装饰的函数bar()被替换成了另一个东西,即被替换成装饰器foo()函数的函数返回值。这个过程大致是:被装饰函数bar()作为参数传入装饰器函数foo(),然后装饰器函数foo()在内部使用这个被传递进来的函数bar(),最后改变了被装饰函数bar()的返回结果。

    由于上面的程序中foo()函数没有返回值,相当于返回值是None,因此被装饰的函数就被替换成了None,因此程序调用print(bar)就看到输出None了。

    # 带一个参数的函数,可作为装饰器函数
    def foo (x):
        print('foo')
        return '万事胜意'
    
    @foo
    #使用@foo装饰bar函数,bar函数是被装饰的函数
    def bar ():
        print('bar')
    
    
    print('------------')
    print(bar)
    
    foo
    ------------
    万事胜意
    

    接着了解下装饰器函数中的参数。装饰器函数需要带一个形参。

    # 带一个参数的函数,可作为装饰器函数
    def foo (x):
        print('foo')
        print(x)
    
    @foo
    #使用@foo装饰bar函数,bar函数是被装饰的函数
    def bar ():
        print('bar')
    
    foo
    <function bar at 0x00000222BFE0E7B8>
    

    上面的程序里,我们只是定义了两个函数,并没有写调用语句,但依旧有结果输出。背后的原因是每次用”@装饰器函数“去装饰其他函数时,装饰器函数就会被调用。

    形参由谁传入值?
    答:Python会自动将被装饰的函数作为参数传入装饰器函数。因此上面程序中装饰器函数foo()中第二行输出x参数,输出的就是被装饰的bar()函数。

    装饰器函数的参数能不能是多个?
    答:每次被装饰的函数只有一个,因此必须有一个、且只要一个参数来接收被装饰的函数。

    前面的例子有些过于简单,日常也不会是返回None。我们希望函数被装饰后返回的还是函数,只要让装饰器函数返回函数即可。

    # 带一个参数的函数,可作为装饰器函数
    def foo (x):
        print('foo')
        return lambda y : print('嘻嘻嘻,', y)
    
    @foo
    #使用@foo装饰bar函数,bar函数是被装饰的函数
    def bar ():
        print('bar')
    
    print('------------')
    print(bar)
    bar('哈哈哈')
    
    foo
    ------------
    <function foo.<locals>.<lambda> at 0x00000222BFE0EB70>
    嘻嘻嘻, 哈哈哈
    

    装饰器函数foo()函数返回了一个lambda表达式,相当于一个函数。按照装饰器的原理,被装饰的bar函数被替换成该lambda表达式,此时bar()函数就可以被调用了。

    bar()函数被替换成了foo()函数返回的lambda表达式,此时bar()函数被彻底替换了。因此bar('哈哈哈')表面上是调用bar函数,其实是调用foo()函数所返回的lambda表达式。

    最终的效果是bar()函数时并没有定义形参,但程序调用bar()函数(表面上是调用bar()函数,实际上是调用foo()函数返回的lambda表达式)却可以传入一个参数(foo()函数返回的lambda表达式定义了一个参数)。

    参考资料:
    关于Python函数装饰器最简单的说明
    Python中的函数高级用法——装饰器

    公众号.png

    相关文章

      网友评论

        本文标题:Py进阶|装饰器

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