python小小白

Py进阶|装饰器

2019-12-31  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读