(TOP)Python简单理解装饰器

没别的意思,稍微记录一下Python装饰器的简单理解

对Python语法尤其是对函数式编程不太熟悉的话可能理解Python的装饰器模式会比较费劲一点,这边简单理解一下Python中的装饰器是个什么东西。

首先,很重要的一点就是Python可以把函数当作对象引用一样传递,所以我们可以把函数当作参数传递给另一个函数,也可以把函数当作另一个函数的返回值,是不是感觉要上天?

加上()的话表示函数在这句代码执行的时候就调用了,不加则表示仅仅当作一个引用传递,并不调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def func_a(func_r1, func_r2):
print func_r1()
return func_r2


def func_b():
return "hi,kyson.I am func b"


def func_c():
return "hi,kyson.I am func c"


if __name__ == '__main__':
print func_a(func_b, func_c)()

一开始看到上面这段的时候其实并没有多少感觉,但是我们只要稍微深究一下就会发现这里面其实可以做很多事情了。

我们可以想一个例子,比如:我现在想要设计一个函数,这个函数可以把其他函数的调用时间打印下来,我们把这个函数暂时命名为:time_cost。

用刚才的想法,我们只需要把任意函数当作参数传到time_cost,然后time_cost调用外部传进来的函数之前和之后计算一下时间,然后打印即可:

1
2
3
4
5
def time_cost2(func_r):
start = time.clock()
func_r()
end = time.clock()
print "cost: %.4f" % (end - start)

这样,我们就可以调用time_cost2函数,并传入真正想要调用的函数,就可以执行函数并打印执行消耗的时间了,cool~

到这里其实装饰器已经完成了,但是还不够。因为每次我们想调用函数的时候只能当作参数传给time_cost2,然后执行time_cost2,这样如果有很多函数需要调用,岂不是每次调用都要换成time_cost2?

这时候Python又露出了蜜汁笑容:不好意思,在我这儿函数名可以赋值给变量

那又怎样?

那就可以把time_cost2函数名称赋值给以真正的函数名称为变量名的变量了!(不好意思,其实很简单的一句话我解释不好)

看看代码吧,就容易理解了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def time_cost2(func_r):
start = time.clock()
func_r()
end = time.clock()
print "cost: %.4f" % (end - start)


def func2():
time.sleep(3)


func2 = time_cost2(func2)

if __name__ == '__main__':
func2()

我在执行func2()的时候你猜怎么着?报错了!

1
2
3
4
Traceback (most recent call last):
File "D:/Dev/Python/Workspace/test/test.py", line 49, in <module>
func2()
TypeError: 'NoneType' object is not callable

会过来看看代码,原来func2在赋值的时候已经是time_cost2(func2)执行了的,所以func2就是time_cost2(func2)的返回值,而并不是可调用的函数,尴尬。

所以问题就变成了,我怎么样让time_cost2(func2)暂时先不执行,当作可调用的函数赋值给func2?

这时候文章开头提到的一点就很重要了:函数可以当作另一个函数的返回值。

所以这时候代码变成了这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def time_cost(func1):
def time_cost_wrap():
start = time.clock()
func1()
end = time.clock()
print "cost: %.4f" % (end - start)

return time_cost_wrap


def func():
time.sleep(3)


func = time_cost(func)

if __name__ == '__main__':
func()

time_cost函数里面定义了time_cost_wrap函数,这个函数做的事情就是刚才time_cost函数做的事情,然后time_cost返回了time_cost_wrap函数,这里注意是返回的函数名称,并没有执行time_cost_wrap,所以当我们把time_cost(func)赋值给func变量的时候,实际上我们是把time_cost_wrap函数赋值给了func,这时候我们再执行func()的时候就相当于执行了time_cost_wrap()。

Perfect.

完成代码:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding:utf-8 -*-
import time


def func_a(func_r1, func_r2):
print func_r1()
return func_r2


def func_b():
return "hi,kyson.I am func b"


def func_c():
return "hi,kyson.I am func c"


def time_cost2(func_r):
start = time.clock()
func_r()
end = time.clock()
print "cost: %.4f" % (end - start)


def func2():
time.sleep(3)


func2 = time_cost2(func2)


def time_cost(func1):
def time_cost_wrap():
start = time.clock()
func1()
end = time.clock()
print "cost: %.4f" % (end - start)

return time_cost_wrap


def func():
time.sleep(3)


func = time_cost(func)

if __name__ == '__main__':
# print func_a(func_b,func_c)
# func2()
func()

ok,写完收工~