装饰器入门
在这里,我们先不用理解实现装饰器需要的几个python特性,以及装饰器的内在原理。
我们仅仅先了解函数装饰器的基本作用,以及怎么实现一个具备基本作用的函数装饰器。
函数装饰器的基本作用:
字面理解,装饰函数用的。其作用也不是很高大上,不过是装饰器,可以对其装饰的函数对象,做一些这个函数执行前的准备工作,以及执行后的请理工作。
工作流程类似于:
setup()
fun()
teardown()
而装饰器不过是改变了其表现形式而已,变成了这样:
@do_it
def fun():
pass
所以,可以理解的是,不使用装饰器,我们依然可以完成目标任务。只是使用装饰器可以是的代码结构更优雅。
实现一个具备基本作用的函数装饰器:
from functools import wraps
def do_it(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('setup')
func(*args, **kwargs)
print('teardown')
return wrapper
@do_it
def my_func():
print("这里是被调用的函数")
if __name__ == "__main__":
my_func()
其输出应该是:
setup
这里是被调用的函数
teardown
[Finished in 1.0s]
再看看被调用函数不被装饰的情况:
from functools import wraps
def do_it(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('setup')
func(*args, **kwargs)
print('teardown')
return wrapper
# @do_it
def my_func():
print("这里是被调用的函数")
if __name__ == "__main__":
my_func()
现在的输出是:
这里是被调用的函数
[Finished in 0.9s]
一些Tips:
from functools improt wraps 、 @wraps(func)这两句是必要的,因为这样可以帮助保留被装饰函数对象的元数据。(元数据是指函数对象本身的一些信息,包含函数名等等)保留元数据在某些时候是必要的。
关于函数装饰器返回值的Tips:
from functools import wraps
def do_it(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('setup')
res = func(*args, **kwargs)
print('my_func的返回值 = {}'.format(res))
print('teardown')
return 2
return wrapper
@do_it
def my_func():
print("这里是被调用的函数")
return 1
if __name__ == "__main__":
rrres = my_func()
print("被装饰的函数执行后的返回值是:{}".format(rrres))
仔细看其输出:
setup
这里是被调用的函数
my_func的返回值 = 1
teardown
被装饰的函数执行后的返回值是:2
[Finished in 0.9s]
上述过程说明了一件事,理解了这件事,也就理解了装饰器的数据流过程:
@do_it
def my_func():
上述语法,当my_func()被调用时,可以理解为我们不是调用的my_func(),而是调用的do_it(my_func),my_func函数对象作为一个输入参数,传递给do_it(),所以最终的返回值,是do_it被调用的返回值。一句话总结:这次调用的输入参数是my_func函数对象,返回值是do_it执行完成的返回值。