装饰器是干什么用的?
装饰器可以在不修改某个函数的情况下, 给函数添加功能.
形象点来说, 从前有一个王叔叔, 他一个人住在家里, 每天打扫家, 看书. 于是定义如下一个函数:
- def uncle_wang():
- sweeping()
- reading()
后来呢, 有一天, 大头儿子一家搬到了王叔叔隔壁 :-D . 根据剧情 https://www.zhihu.com/question/25105038 , 一天, 大头儿子的妈妈请王叔叔来家里吃饭, 那么, 王叔叔的日程就添加了 "去隔壁吃饭" 这一项, 但是又不能修改王叔叔之前的日程, 怎么实现? 这时, 就可以给王叔叔添加一个装饰器, 给这个装饰器起个名字, 姑且就叫 neighbor, 然后就写成这样:
- @neighbor
- def uncle_wang():
- sweeping()
- reading()
然后王叔叔去大头儿子家吃饭就提上日程啦, 哈哈.(只是吃饭哦, 不要想多了(⊙v⊙))
这个 neighbor 其实也是个函数, 参数就是 uncle_wang(没错, 可以把函数名当成参数传来传去, 还能当做返回值), 在装饰器里面实现 "去隔壁吃饭":
- def neighbor(func):
- eat_next_door() # 自定义函数, 去隔壁吃饭
- return func # 原来的函数不变, 直接返回
最后是执行, 直接运行 uncle_wang()即可
- # 执行函数
- uncle_wang() # 相当于不加装饰器, 直接执行 neighbor(uncle_wang)()
这感觉就像是用 neighbor 装饰了 uncle_wang, 丰富了王叔叔的生活, 从此变成了隔壁老王. 实现方式就是套娃, 给 uncle_wang 套个 neighbor, 变成 neighbor(uncle_wang)(这整个东西是个函数名), 然后调用这个函数: neighbor(uncle_wang)(), 形如: 函数名()
在 Python 里, 这个套娃的操作简化成了装饰器, 直接在原函数上面添加 @neighbor, 然后调用的时候还是写成 uncle_wang(), 但是这个装饰过的王叔叔已经不是原来的王叔叔了, 他现在其实是隔壁老王.
王叔叔的新日程搞定了, 但是还有个问题, 就是顺序. 现在的日程顺序相当于:
- eat_next_door()
- sweeping()
- reading()
请人吃饭当然是吃晚饭啦, 所以 eat_next_door()需要排在最后面, 而 neighbor 函数不能先返回 (return func) 然后才执行 eat_next_door(), 众所周知, 函数返回了就结束了, 后面的东西都不管了.
所以, 继续套娃, 再搞个函数进去, 写成这样:
- def neighbor(func):
- def wrapper(): # 套娃函数, 注意这里是定义, 不是执行
- func() # 相当于不带装饰器的 uncle_wang()
- eat_next_door() # 自定义函数, 去隔壁吃饭
- return wrapper # 直接返回套娃函数
这样顺序就对了, 王叔叔很满意~
现在这个装饰器基本成型了, 但是现在还不能处理原函数的参数和装饰器函数的参数, 继续改进的实现方式可以去看廖雪峰老师的教程, 写得很不错, 我就是从那学来的.
附上完整代码:
- # !/usr/bin/env python3
- # -*- coding: utf-8 -*-
- def sweeping():
- print('sweeping')
- def reading():
- print('reading')
- def eat_next_door():
- print('eat_next_door')
- def neighbor(func):
- def wrapper(): # 套娃函数, 注意这里是定义, 不是执行
- func() # 相当于不带装饰器的 uncle_wang()
- eat_next_door() # 自定义函数, 去隔壁吃饭
- return wrapper # 直接返回套娃函数
- @neighbor
- def uncle_wang():
- sweeping()
- reading()
- if __name__ == "__main__":
- uncle_wang()
- (嗨, 又水了一篇, 之前还说要测一下手动实现和库函数实现的二分查找的耗时差距, 正事还是放到下次吧......)
参考资料:
装饰器 - 廖雪峰的官方网站
隔壁老王的梗是怎么来的 - 知乎 https://www.zhihu.com/question/25105038
来源: https://www.cnblogs.com/adjwang/p/12270094.html