欢迎关注微信公众号“Python小灶,和我一起每天学习Python新知识”
不积跬步,无以至千里;不积小流,无以成江海。每天进步一点点,也是很大的进步。
一、什么是装饰器
这是我从官方文档接下来的图,虽然现在官方文档已经有中文版了,但是众所周知,中文文档是需要翻译的。
二、别给老夫讲原理,老夫写代码就是一把梭
观众老爷可能不满了,这都是啥,还是不明白。
简单来讲,装饰器就是在不改变原有代码结构的基础上,添加新功能。
示例:现在想在打印“Hello World”之前想再打印个"Hello Python"
def fun():
print("Hello World")
if __name__ == "__main__":
fun()
这个例子可能举的不是太好,可能比较机智的同学已经忍不住冷笑了。
def fun():
print("Hello World")
if __name__ == "__main__":
print("Hello Python")
fun()
当然,你知道我不是这个意思,所以我们来个实际点的例子:
(当函数多、功能复杂的时候,上面那个方法不好使,特别容易污染工程代码,而且我这是举的最简单的例子,大部分函数是为了实现某一功能,是比较复杂的)
想在要在每一个函数的开头和结尾分别加上:这是函数XX的开头以及这是函数XX的结尾
def fun1():
print("这是函数{}的主体".format(fun1.__name__))
def fun2():
print("这是函数{}的主体".format(fun2.__name__))
if __name__ == "__main__":
fun1()
fun2()
# 这是函数fun1的主体
# 这是函数fun2的主体
那么如何实现
def a_decorator(fun):
def wrapTheFunction():
print("这是函数{}的开头".format(fun.__name__))
fun()
print("这是函数{}的结尾".format(fun.__name__))
return wrapTheFunction
@a_decorator
def fun1():
print("这是函数{}的主体".format(fun1.__name__))
@a_decorator
def fun2():
print("这是函数{}的主体".format(fun2.__name__))
if __name__ == "__main__":
fun1()
fun2()
# 这是函数fun1的开头
# 这是函数wrapTheFunction的主体
# 这是函数fun1的结尾
# 这是函数fun2的开头
# 这是函数wrapTheFunction的主体
# 这是函数fun2的结尾
恭喜,你已经学会了装饰器,当然你可能发现了一点问题,就是打印不太对劲,这里的函数被warpTheFunction替代了。它重写了我们函数的名字和注释文档(docstring)。我举得例子因为刚好用到函数名,其实如果不需要用到函数名的装饰器不需要关注这个,如果一定要用到,解决办法就是那就是 functools.wraps
from functools import wraps
def a_decorator(fun):
@wraps(fun)
def wrapTheFunction():
print("这是函数{}的开头".format(fun.__name__))
fun()
print("这是函数{}的结尾".format(fun.__name__))
return wrapTheFunction
@a_decorator
def fun1():
print("这是函数{}的主体".format(fun1.__name__))
@a_decorator
def fun2():
print("这是函数{}的主体".format(fun2.__name__))
if __name__ == "__main__":
fun1()
fun2()
# 这是函数fun1的开头
# 这是函数fun1的主体
# 这是函数fun1的结尾
# 这是函数fun2的开头
# 这是函数fun2的主体
# 这是函数fun2的结尾
怎么样,是不是简单又有趣又实用,你学废了吗?
三、知其然,也想知其所以然
接下来我就给各位观众老爷翻译翻译,什么叫装饰器。
- 装饰器是一个函数;
- 函数都有返回值,装饰器的返回值也是函数;
- 装饰器语法是一种语法糖(一种封装)。
怎么来理解上述内容?,还是以上面示例为例。
在Python中,一切皆是对象,变量是,函数也是,所以函数可以作为参数传递,也可以当成返回值。
带着这个认知,我们去看看装饰器发生了什么(顺序1234)。
# 2、函数走到这里,a_decorator里定义了wrapTheFunction
# 但是只是定义,没有调用,整个a_decorator返回wrapTheFunction
def a_decorator(fun):
def wrapTheFunction():
print("Hello Python")
fun()
return wrapTheFunction
def fun():
print("Hello World")
# 1、调用a_decorator函数,并把fun作为参数传给它
# 注意,不能加(),否则直接就执行了
fun = a_decorator(fun) # 3、把调用的结果wrapTheFunction赋值给fun
if __name__ == "__main__":
fun() # 4、fun()此时就等于运行 wrapTheFunction()
# Hello Python
# Hello World
把上述代码封装成如下形式,就是装饰器。
@a_decorator
def fun():
print("Hello World")
if __name__ == "__main__":
fun()
可能有些人对fun和fun()很困惑,其实很好理解,fun是指这个函数,fun()是指这个函数调用的结果。
四、进阶,带参数的装饰器
待补充
五、参考文献,资料
想了解的更详细,去看以下两篇文档哦。
Python进阶_装饰器
菜鸟教程_装饰器