Python的修饰器
先看一个很常见的例子
req.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def before_request(func): def inner(*args, **kwargs): print('before_request...', args, kwargs) return func(*args, **kwargs) return inner def after_request(func): def inner(*args, **kwargs): result = func(*args, **kwargs) print('after_request...') return result return inner @after_request @before_request def index(a,b,c): print('render index.....') if __name__ == '__main__': index([],2,c='fk')
|
输出
1 2 3
| before_request... ([], 2) {'c': 'fk'} render index..... after_request...
|
原理解释
你写了一个很棒的通用方法,但是有点长。但是老板这时候来了需求,要求它在不同的情况下进行一些不同的操作(例如不同情境下的验证操作)。为了遵循封闭开发原则,尽量不去改已经完成的代码,或许修饰器是一个不错而优雅的选择。
先举个简单例子
1 2 3 4 5 6 7
| def awesome_method(): print('main func') def before_do_that(): print('before func')
|
你想在函数awesome_method
前先执行before_do_that
,并且要在同一个context下,如果直接修改通用代码,不仅不简洁,而且不优雅。这个时候你利用修饰符稍加修改:
1 2 3 4 5 6 7 8 9 10 11
| @before_do_that def awesome_method(): print('main func') def before_do_that(func): def inner(): print('before func') return func() return inner
|
这里解释一下,在一个函数添加一个修饰符,相当于把awesome_method作为before_do_that的参数,转换成了一个新的同名函数,这里的before_do_that相当于一个工厂,进去的函数都必须通过加工。
那么多个修饰符的情况下,代码执行顺序如何?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def w1(func): def inner(): print('w1 ready go') return func() return inner def w2(func): def inner(): print('w2 ready go') return func() return inner @w2 @w1 def f1(): print('f1')
|
若执行f1()
,此时相当于
输出
1 2 3
| w2 ready go w1 ready go f1
|
带参数写法如下,这次用after
举例
1 2 3 4 5 6 7 8 9 10
| def after_request(func): def inner(*args, **kwargs): result = func(*args, **kwargs) print('after_request...', args, kwargs) return result return inner @after_request def index(a,b,c): print('render index.....')
|
此时执行 index([],2,c='fk')
,输出:
1 2
| render index..... after_request... ([], 2) {'c': 'fk'}
|
**
表示对键值对的引用,关于**
的用法,我们可以甚至可以写一个漂亮的字典构造函数:
1 2 3
| >>> a=lambda **x:x >>> a(a=2,c=2) {'c': 2, 'a': 2}
|
如果多个修饰符写的不好看,还有修饰符带参数的闭包写法
dec.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| def Before(request, kargs): print('some thing before..') def After(request, kargs): print('some thing after..') def Filter(before_func, after_func): def outer(main_func): def wrapper(request, kargs): before_result = before_func(request, kargs) if (before_result != None): return before_result main_result = main_func(request, kargs) if (main_result != None): return main_result after_result = after_func(request, kargs) if (after_result != None): return after_result return wrapper return outer @Filter(Before, After) def Index(request, kargs): print('index') if __name__ == '__main__': Index([],2,c='fk')
|
这个闭包利用了Filter
和outer
的三个参数函数,重新改写执行顺序,直到其中有一个函数抛出返回值为止。
至此关于修饰符的内容基本交代完毕
多线程
// Todo: