装饰器
代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
其实弄明白了python中的嵌套函数(也就是所谓的闭合函数)之后,再想搞懂python装饰器就简单多了。总之python装饰器不过就是一个针对嵌套函数的语法糖 。它的作用就是在函数调用方法不变的情况下,把此函数包装成另一个函数来使用。
一、首先来大致了解一下嵌套函数
被嵌套与一层函数中的二层函数可以记录上上一层函数作用域中的变量。
1
2
3
4
5
6
7
|
def
foo(a):
def
subfoo(b):
return
(b
+
a)
return
(subfoo)
f
=
foo(
'content'
)
#由于foo返回的是subfoo,所以f是对subfoo的引用
print
(f(
'sub_'
))
#因为subfoo记录了foo的参数变量'content',所以返回值为'sub_content'
|
二、嵌套函数变种装饰器
以下两段代码作用是相同的
1
2
3
4
5
6
7
8
9
10
|
def
action(x):
return
(x)
def
action_pro(n):
def
warpper(x):
return
(n(x)
*
x)
return
(warpper)
action
=
action_pro(action)
#第一个action为自定义的伪装变量,第二个action为上边定义的action函数
print
(action(
3
))
#此函数实际warpper(3),返回值为9
|
将上面代码改写
1
2
3
4
5
6
7
8
|
def
action_pro(n):
def
warpper(x):
return
(n(x)
*
x)
return
(warpper)
@action_pro
#用action_pro函数把action包装成warpper
def
action(x):
return
(x)
print
(action(
3
))
#此函数实际warpper(3),返回值为9
|
如果装饰器本身需要传入参数,那就需要编写一个返回装饰器的函数,无参数的装饰器就是把把sum函数装饰为一个新的函数。带参数的装饰器是什么样的呢?带参数的装饰器先处理参数,然后再生成一个新的装饰器函数,最后把新函数起个别名,写出来会比较复杂。代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def
before():
print
(
'before'
)
def
after():
print
(
'after'
)
def
filter
(before_fun,after_fun):
def
outer(main_fun):
def
wrpper(
*
args,
*
*
kargs):
before_fun()
main_fun()
after()
return
wrpper
return
outer
@filter
(before,after)
def
index():
print
(
'index'
)
index()
|
还有没有办法实现即支持不带参数,又支持带参数的装饰器呢(代码没看懂,需要仔细研究)
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
|
import
functools
def
log(argument):
if
not
callable
(argument):
def
decorator(function):
@functools
.wraps(function)
def
wrapper(
*
args,
*
*
kwargs):
print
(
'before function [%s()] run, text: [%s].'
%
(function.__name__, argument))
rst
=
function(
*
args,
*
*
kwargs)
print
(
'after function [%s()] run, text: [%s].'
%
(function.__name__, argument))
return
rst
return
wrapper
return
decorator
def
wrapper(
*
args,
*
*
kwargs):
print
(
'before function run.'
)
argument(
*
args,
*
*
kwargs)
print
(
'after function run.'
)
return
wrapper
@log
def
func():
print
(
'func() run.'
)
@log
(
'log text'
)
def
func1():
print
(
'func() run without parameter'
)
if
'__main__'
=
=
__name__:
func()
func1()
|