python 语法糖 - 装饰器

python decorator

前几天,小A同学问到了怎么写装饰器的问题

给我的代码是:

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
# coding: utf-8
class test:
i = 1
def start(self):
print 'start'+str(self.i)
def end(self):
print 'end'+str(self.i)
def do1(self):
self.start()
print self.i
self.end()
def do2(self):
self.start()
print self.i
self.end()
t = test()
t.do1()
print '----'*10
t.do2()

语法糖怎么能不会呢

改成装饰器之后是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def hello(fc):
def wrapper(*args, **kwargs):
print 'start' + str(args[0].i)
r = fc(*args, **kwargs)
print 'end' + str(args[0].i)
return r
return wrapper
class test:
i =1
@hello
def do1(self):
print '-'*10
t = test()
t.do1()

好像很简单的样子

滴—–
司机卡

然而如果加一句

1
print t.do1.__name__

这个输出似乎有什么问题呢

1
2
3
4
5
$ python decorator.py
start1
----------
end1
wrapper

属性丢失了

解决办法是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from functools import wraps
def hello(fc):
@wraps(fc)
def wrapper(*args, **kwargs):
print 'start' + str(args[0].i)
r = fc(*args, **kwargs)
print 'end' + str(args[0].i)
return r
return wrapper
class test:
i =1
@hello
def do1(self):
print '-'*10
t = test()
t.do1()
print t.do1.__name__

关于wraps官方文档里这么解释

  • Without the use of this decorator factory, the name of the example function would have been ‘wrapper’, and the docstring of the original example() would have been lost.

最后用来解决一下我今天需要的定时超时的问题

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
def timeout(seconds, error_message="Timeout Error: the cmd 300s have not finished."):
def decorated(func):
result = ""
def _handle_timeout(signum, frame):
global result
result = error_message
raise Exception(error_message)
@wraps(func)
def wrapper(*args, **kwargs):
global result
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
result = func(*args, **kwargs)
# try:
# result = func(*args, **kwargs)
# finally:
# return result
return result
return wrapper
return decorated

Python/Security<br>程序媛<br><br>小狐狸.