由于没时间编写,就把几张写的不错的文章摘录整合到一起。原文地址:Python Decorator python decorator心得体会 可爱的 Python: Decorator 简化元编程
Python之美--Decorator深入详解(一) Python Decorators(二):Decorator参数 Python Decorator初体验
Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西。在认识装饰器之前,我们先来点感性认识,看一个Python修饰器的Hello World的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
下面是代码:文件名:hello.py
def
hello(fn):
def
wrapper():
print
"hello, %s"
%
fn.__name__
fn()
print
"goodby, %s"
%
fn.__name__
return
wrapper
@hello
def
foo():
print
"i am foo"
foo()
|
当你运行代码,你会看到如下输出:
1
2
3
4
|
[chenaho@chenhao
-
air]$ python hello.py
hello, foo
i am foo
goodby, foo
|
你可以看到如下的东西:
1)函数foo前面有个@hello的“注解”,hello就是我们前面定义的函数hello;
2)在hello函数中,其需要一个fn的参数(这就用来做回调的函数);
3)hello函数中返回了一个inner函数wrapper,这个wrapper函数回调了传进来的fn,并在回调前后加了两条语句。
Decorator 的本质
对于Python的这个@注解语法糖- Syntactic Sugar 来说,当你在用某个@decorator来修饰某个函数func时,如下所示:
1
2
3
|
@decorator
def
func():
pass
|
其解释器会解释成下面这样的语句:
1
|
func
=
decorator(func)
|
了然,这不就是把一个函数当参数传到另一个函数中,然后再回调吗?是的,但是,我们需要注意,那里还有一个赋值语句,把decorator这个函数的返回值赋值回了原来的func。 根据《函数式编程》中的first class functions中的定义的,你可以把函数当成变量来使用,所以,decorator必需得返回了一个函数出来给func,这就是所谓的higher order function 高阶函数,不然,后面当func()调用的时候就会出错。 就我们上面那个hello.py里的例子来说,
1
2
3
|
@hello
def
foo():
print
"i am foo"
|
被解释成了:
1
|
foo
=
hello(foo)
|
是的,这是一条语句,而且还被执行了。你如果不信的话,你可以写这样的程序来试试看:
1
2
3
4
5
6
|
def
fuck(fn):
print
"fuck %s!"
%
fn.__name__[::
-
1
].upper()
@fuck
def
wfg():
pass
|
没了,就上面这段代码,没有调用wfg()的语句,你会发现, fuck函数被调用了,而且还很NB地输出了我们每个人的心声!
再回到我们hello.py的那个例子,我们可以看到,hello(foo)返回了wrapper()函数,所以,foo其实变成了wrapper的一个变量,而后面的foo()执行其实变成了wrapper()。知道这点本质,当你看到有多个decorator或是带参数的decorator,你也就不会害怕了。
比如:多个decorator:
1
2
3
4
|
@decorator_one
@decorator_two
def
func():
pass
|
相当于:
1
|
func
=
decorator_one(decorator_two(func))
|
比如:带参数的decorator:
1
2
3
|
@decorator
(arg1, arg2)
def
func():
pass
|
相当于:
1
|
func
=
decorator(arg1,arg2)(func)
|
这意味着decorator(arg1, arg2)这个函数需要返回一个“真正的decorator”。
带参数及多个Decrorator
我们来看一个有点意义的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
makeHtmlTag(tag,
*
args,
*
*
kwds):
def
real_decorator(fn):
css_class
=
" class='{0}'"
.
format
(kwds[
"css_class"
])
if
"css_class"
in
kwds
else
""
def
wrapped(
*
args,
*
*
kwds):
return
"<"
+
tag
+
css_class
+
">"
+
fn(
*
args,
*
*
kwds)
+
"</"
+
tag
+
">"
return
wrapped
return
real_decorator
@makeHtmlTag
(tag
=
"b"
, css_class
=
"bold_css"
)
@makeHtmlTag
(tag
=
"i"
, css_class
=
"italic_css"
)
def
hello():
return
"hello world"
print
hello()
# 输出:
# <b class='bold_css'><i class='italic_css'>hello world</i></b>
|
在上面这个例子中,我们可以看到:makeHtmlTag有两个参数。所以,为了让 hello = makeHtmlTag(arg1, arg2)(hello) 成功,makeHtmlTag 必需返回一个decorator(这就是为什么我们在makeHtmlTag中加入了real_decorator()的原因),这样一来,我们就可以进入到 decorator 的逻辑中去了—— decorator得返回一个wrapper,wrapper里回调hello。看似那个makeHtmlTag() 写得层层叠叠,但是,已经了解了本质的我们觉得写得很自然。
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
初识Decorator
Decorator,修饰符,是在Python2.
4
中增加的功能,也是pythoner实现元编程的最新方式,同时它也是最简单的元编程方式。为什么是“最简单”呢?是的,其实在Decorator之前就已经
有
classmethod
()和
staticmethod
()内置函数,但他们的缺陷是会导致函数名的重复使用(可以看看David Mertz的Charming Python: Decorators make magic easy ),
以下是摘自他本人的原文:
class
C:
def
foo(
cls
, y):
print
"classmethod"
,
cls
, y
foo
=
classmethod
(foo)
是的,
classmethod
做的只是函数转换,但是它却让foo这个名字另外出现了
2
次。记得有一句话是:人类因懒惰而进步。Decorator的诞生,让foo少出现
2
次。
class
C:
@classmethod
def
foo(
cls
, y):
print
"classmethod"
,
cls
, y
读者也许已经想到Decorator在python中是怎么处理的了(如果还没头绪的,强烈建议先去看看limodou写的Decorator学习笔记 )。下面我列出
4
种用法。
单个 Decorator,不带参数
设想一个情景,你平时去买衣服的时候,跟售货员是怎么对话的呢?售货员会先向你问好,然后你会试穿某件你喜爱的衣服。
def
salesgirl(method):
def
serve(
*
args):
print
"Salesgirl:Hello, what do you want?"
, method.__name__
method(
*
args)
return
serve
@salesgirl
def
try_this_shirt(size):
if
size <
35
:
print
"I: %d inches is to small to me"
%
(size)
else
:
print
"I:%d inches is just enough"
%
(size)
try_this_shirt(
38
)
结果是:
Salesgirl:Hello, what do you want? try_this_shirt
I:
38
inches
is
just enough
这只是一个太简单的例子,以至一些“细节”没有处理好,你试穿完了好歹也告诉salesgirl到底要不要买啊。。。这样try_this_shirt方法需要改成带返回值
(假设是
bool
类型,
True
就是要买,
False
就是不想买),那么salesgirl中的serve也应该带返回值,并且返回值就是 method(
*
args)。
修改后的salesgirl
def
salesgirl(method):
def
serve(
*
args):
print
"Salesgirl:Hello, what do you want?"
, method.__name__
return
method(
*
args)
return
serve
@salesgirl
def
try_this_shirt(size):
if
size <
35
:
print
"I: %d inches is to small to me"
%
(size)
return
False
else
:
print
"I:%d inches is just enough"
%
(size)
return
True
result
=
try_this_shirt(
38
)
print
"Mum:do you want to buy this?"
, result
结果是:
Salesgirl:Hello, what do you want? try_this_shirt
I:
38
inches
is
just enough
Mum:do you want to buy this?
True
现在我们的salesgirl还不算合格,她只会给客人打招呼,但是客人要是买衣服了,也不会给他报价;客人不买的话,也应该推荐其他款式!
会报价的salesgirl:
def
salesgirl(method):
def
serve(
*
args):
print
"Salesgirl:Hello, what do you want?"
, method.__name__
result
=
method(
*
args)
if
result:
print
"Salesgirl: This shirt is 50$."
else
:
print
"Salesgirl: Well, how about trying another style?"
return
result
return
serve
@salesgirl
def
try_this_shirt(size):
if
size <
35
:
print
"I: %d inches is to small to me"
%
(size)
return
False
else
:
print
"I:%d inches is just enough"
%
(size)
return
True
result
=
try_this_shirt(
38
)
print
"Mum:do you want to buy this?"
, result
结果是:
Salesgirl:Hello, what do you want? try_this_shirt
I:
38
inches
is
just enough
Salesgirl: This shirt
is
50
$.
Mum:do you want to buy this?
True
这样的salesgirl总算是合格了,但离出色还很远,称职的salesgirl是应该对熟客让利,老用户总得有点好处吧?
单个 Decorator,带参数
会报价并且带折扣的salesgirl:
def
salesgirl(discount):
def
expense(method):
def
serve(
*
args):
print
"Salesgirl:Hello, what do you want?"
, method.__name__
result
=
method(
*
args)
if
result:
print
"Salesgirl: This shirt is 50$.As an old user, we promised to discount at %d%%"
%
(discount)
else
:
print
"Salesgirl: Well, how about trying another style?"
return
result
return
serve
return
expense
@salesgirl
(
50
)
def
try_this_shirt(size):
if
size <
35
:
print
"I: %d inches is to small to me"
%
(size)
return
False
else
:
print
"I:%d inches is just enough"
%
(size)
return
True
result
=
try_this_shirt(
38
)
print
"Mum:do you want to buy this?"
, result
结果是:
Salesgirl:Hello, what do you want? try_this_shirt
I:
38
inches
is
just enough
Salesgirl: This shirt
is
50
$.As an old user, we promised to discount at
50
%
Mum:do you want to buy this?
True
这里定义的salesgirl是会给客户
50
%
的折扣,因为salesgirl描述符是带参数,而参数就是折扣。如果你是第一次看到这个 salesgirl,
会被她里面嵌套的
2
个方法而感到意外,没关系,当你习惯了Decorator之后,一切都变得很亲切啦
|
你看,Python的Decorator就是这么简单,没有什么复杂的东西,你也不需要了解过多的东西,使用起来就是那么自然、体贴,但是你觉得上面那个带参数的Decorator的函数嵌套太多了,你受不了。好吧,没事,我们看看下面的方法。
class式的 Decorator(重点)
1、首先,先得说一下,decorator的class方式,还是看个示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class
myDecorator(
object
):
def
__init__(
self
, fn):
print
"inside myDecorator.__init__()"
self
.fn
=
fn
def
__call__(
self
):
self
.fn()
print
"inside myDecorator.__call__()"
@myDecorator
def
aFunction():
print
"inside aFunction()"
print
"Finished decorating aFunction()"
aFunction()
# 输出:
# inside myDecorator.__init__()
# Finished decorating aFunction()
# inside aFunction()
# inside myDecorator.__call__()
|
上面这个示例展示了,用类的方式声明一个decorator。我们可以看到这个类中有两个成员:
1)一个是__init__(),这个方法是在我们给某个函数decorator时被调用,所以,需要有一个fn的参数,也就是被decorator的函数。
2)一个是__call__(),这个方法是在我们调用被decorator函数时被调用的。
上面输出可以看到整个程序的执行顺序。这看上去要比“函数式”的方式更易读一些。
2、下面,我们来看看用类的方式来重写上面的html.py的代码:html.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class
makeHtmlTagClass(
object
):
def
__init__(
self
, tag, css_class
=
""):
self
._tag
=
tag
self
._css_class
=
" class='{0}'"
.
format
(css_class) \
if
css_class !
=
"
" else "
"
def
__call__(
self
, fn):
def
wrapped(
*
args,
*
*
kwargs):
return
"<"
+
self
._tag
+
self
._css_class
+
">"
\
+
fn(
*
args,
*
*
kwargs)
+
"</"
+
self
._tag
+
">"
return
wrapped
@makeHtmlTagClass
(tag
=
"b"
, css_class
=
"bold_css"
)
@makeHtmlTagClass
(tag
=
"i"
, css_class
=
"italic_css"
)
def
hello(name):
return
"Hello, {}"
.
format
(name)
print
hello(
"Hao Chen"
)
|
上面这段代码中,我们需要注意这几点:
1)如果decorator有参数的话,__init__() 成员就不能传入fn了,而fn是在__call__的时候传入的。
2)这段代码还展示了 wrapped(*args, **kwargs) 这种方式来传递被decorator函数的参数。(其中:args是一个参数列表,kwargs是参数dict,具体的细节,请参考Python的文档或是StackOverflow的这个问题,这里就不展开了)
3、用Decorator设置函数的调用参数,你有三种方法可以干这个事:
第一种,通过 **kwargs,这种方法decorator会在kwargs中注入参数。
1
2
3
4
5
6
7
8
9
10
11
|
def
decorate_A(function):
def
wrap_function(
*
args,
*
*
kwargs):
kwargs[
'str'
]
=
'Hello!'
return
function(
*
args,
*
*
kwargs)
return
wrap_function
@decorate_A
def
print_message_A(
*
args,
*
*
kwargs):
print
(kwargs[
'str'
])
print_message_A()
|
第二种,约定好参数,直接修改参数
1
2
3
4
5
6
7
8
9
10
11
|
def
decorate_B(function):
def
wrap_function(
*
args,
*
*
kwargs):
str
=
'Hello!'
return
function(
str
,
*
args,
*
*
kwargs)
return
wrap_function
@decorate_B
def
print_message_B(
str
,
*
args,
*
*
kwargs):
print
(
str
)
print_message_B()
|
第三种,通过 *args 注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def
decorate_C(function):
def
wrap_function(
*
args,
*
*
kwargs):
str
=
'Hello!'
#args.insert(1, str)
args
=
args
+
(
str
,)
return
function(
*
args,
*
*
kwargs)
return
wrap_function
class
Printer:
@decorate_C
def
print_message(
self
,
str
,
*
args,
*
*
kwargs):
print
(
str
)
p
=
Printer()
p.print_message()
|
Decorator的副作用
到这里,我相信你应该了解了整个Python的decorator的原理了。相信你也会发现,被decorator的函数其实已经是另外一个函数了,对于最前面那个hello.py的例子来说,如果你查询一下foo.__name__的话,你会发现其输出的是“wrapper”,而不是我们期望的“foo”,这会给我们的程序埋一些坑。所以,Python的functool包中提供了一个叫wrap的decorator来消除这样的副作用。下面是我们新版本的hello.py。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
文件名:hello.py
from
functools
import
wraps
def
hello(fn):
@wraps
(fn)
def
wrapper():
print
"hello, %s"
%
fn.__name__
fn()
print
"goodby, %s"
%
fn.__name__
return
wrapper
@hello
def
foo():
'''foo help doc'''
print
"i am foo"
pass
foo()
print
foo.__name__
#输出 foo
print
foo.__doc__
#输出 foo help doc
|
当然,即使是你用了functools的wraps,也不能完全消除这样的副作用。来看下面这个示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
from
inspect
import
getmembers, getargspec
from
functools
import
wraps
def
wraps_decorator(f):
@wraps
(f)
def
wraps_wrapper(
*
args,
*
*
kwargs):
return
f(
*
args,
*
*
kwargs)
return
wraps_wrapper
class
SomeClass(
object
):
@wraps_decorator
def
method(
self
, x, y):
pass
obj
=
SomeClass()
for
name, func
in
getmembers(obj, predicate
=
inspect.ismethod):
print
"Member Name: %s"
%
name
print
"Func Name: %s"
%
func.func_name
print
"Args: %s"
%
getargspec(func)[
0
]
# 输出:
# Member Name: method
# Func Name: method
# Args: []
|
你会发现,即使是你你用了functools的wraps,你在用getargspec时,参数也不见了。要修正这一问,我们还得用Python的反射来解决,下面是相关的代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
def
get_true_argspec(method):
argspec
=
inspect.getargspec(method)
args
=
argspec[
0
]
if
args
and
args[
0
]
=
=
'self'
:
return
argspec
if
hasattr
(method,
'__func__'
):
method
=
method.__func__
if
not
hasattr
(method,
'func_closure'
)
or
method.func_closure
is
None
:
raise
Exception(
"No closure for method."
)
method
=
method.func_closure[
0
].cell_contents
return
get_true_argspec(method)
|
当然,我相信大多数人的程序都不会去getargspec。所以,用functools的wraps应该够用了。一些decorator的示例。好了,现在我们来看一下各种decorator的例子:给函数调用做缓存。这个例实在是太经典了,整个网上都用这个例子做decorator的经典范例,因为太经典了,所以,我这篇文章也不能免俗。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
from
functools
import
wraps
def
memo(fn):
cache
=
{}
miss
=
object
()
@wraps
(fn)
def
wrapper(
*
args):
result
=
cache.get(args, miss)
if
result
is
miss:
result
=
fn(
*
args)
cache[args]
=
result
return
result
return
wrapper
@memo
def
fib(n):
if
n <
2
:
return
n
return
fib(n
-
1
)
+
fib(n
-
2
)
|
上面这个例子中,是一个斐波拉契数例的递归算法。我们知道,这个递归是相当没有效率的,因为会重复调用。比如:我们要计算fib(5),于是其分解成fib(4) + fib(3),而fib(4)分解成fib(3)+fib(2),fib(3)又分解成fib(2)+fib(1)…… 你可看到,基本上来说,fib(3), fib(2), fib(1)在整个递归过程中被调用了两次。而我们用decorator,在调用函数前查询一下缓存,如果没有才调用了,有了就从缓存中返回值。一下子,这个递归从二叉树式的递归成了线性的递归。
Profiler的例子
这个例子没什么高深的,就是实用一些。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
cProfile, pstats, StringIO
def
profiler(func):
def
wrapper(
*
args,
*
*
kwargs):
datafn
=
func.__name__
+
".profile"
# Name the data file
prof
=
cProfile.Profile()
retval
=
prof.runcall(func,
*
args,
*
*
kwargs)
#prof.dump_stats(datafn)
s
=
StringIO.StringIO()
sortby
=
'cumulative'
ps
=
pstats.Stats(prof, stream
=
s).sort_stats(sortby)
ps.print_stats()
print
s.getvalue()
return
retval
return
wrapper
|
注册回调函数
下面这个示例展示了通过URL的路由来调用相关注册的函数示例:
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
|
class
MyApp():
def
__init__(
self
):
self
.func_map
=
{}
def
register(
self
, name):
def
func_wrapper(func):
self
.func_map[name]
=
func
return
func
return
func_wrapper
def
call_method(
self
, name
=
None
):
func
=
self
.func_map.get(name,
None
)
if
func
is
None
:
raise
Exception(
"No function registered against - "
+
str
(name))
return
func()
app
=
MyApp()
@app
.register(
'/'
)
def
main_page_func():
return
"This is the main page."
@app
.register(
'/next_page'
)
def
next_page_func():
return
"This is the next page."
print
app.call_method(
'/'
)
print
app.call_method(
'/next_page'
)
|
注意:
1)上面这个示例中,用类的实例来做decorator。
2)decorator类中没有__call__(),但是wrapper返回了原函数。所以,原函数没有发生任何变化。
给函数打日志
下面这个示例演示了一个logger的decorator,这个decorator输出了函数名,参数,返回值,和运行时间。
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
|
from
functools
import
wraps
def
logger(fn):
@wraps
(fn)
def
wrapper(
*
args,
*
*
kwargs):
ts
=
time.time()
result
=
fn(
*
args,
*
*
kwargs)
te
=
time.time()
print
"function = {0}"
.
format
(fn.__name__)
print
" arguments = {0} {1}"
.
format
(args, kwargs)
print
" return = {0}"
.
format
(result)
print
" time = %.6f sec"
%
(te
-
ts)
return
result
return
wrapper
@logger
def
multipy(x, y):
return
x
*
y
@logger
def
sum_num(n):
s
=
0
for
i
in
xrange
(n
+
1
):
s
+
=
i
return
s
print
multipy(
2
,
10
)
print
sum_num(
100
)
print
sum_num(
10000000
)
|
上面那个打日志还是有点粗糙,让我们看一个更好一点的(带log level参数的):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import
inspect
def
get_line_number():
return
inspect.currentframe().f_back.f_back.f_lineno
def
logger(loglevel):
def
log_decorator(fn):
@wraps
(fn)
def
wrapper(
*
args,
*
*
kwargs):
ts
=
time.time()
result
=
fn(
*
args,
*
*
kwargs)
te
=
time.time()
print
"function = "
+
fn.__name__,
print
" arguments = {0} {1}"
.
format
(args, kwargs)
print
" return = {0}"
.
format
(result)
print
" time = %.6f sec"
%
(te
-
ts)
if
(loglevel
=
=
'debug'
):
print
" called_from_line : "
+
str
(get_line_number())
return
result
return
wrapper
return
log_decorator
|
但是,上面这个带log level参数的有两具不好的地方,
1) loglevel不是debug的时候,还是要计算函数调用的时间。
2) 不同level的要写在一起,不易读。
我们再接着改进:
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
|
mport inspect
def
advance_logger(loglevel):
def
get_line_number():
return
inspect.currentframe().f_back.f_back.f_lineno
def
_basic_log(fn, result,
*
args,
*
*
kwargs):
print
"function = "
+
fn.__name__,
print
" arguments = {0} {1}"
.
format
(args, kwargs)
print
" return = {0}"
.
format
(result)
def
info_log_decorator(fn):
@wraps
(fn)
def
wrapper(
*
args,
*
*
kwargs):
result
=
fn(
*
args,
*
*
kwargs)
_basic_log(fn, result, args, kwargs)
return
wrapper
def
debug_log_decorator(fn):
@wraps
(fn)
def
wrapper(
*
args,
*
*
kwargs):
ts
=
time.time()
result
=
fn(
*
args,
*
*
kwargs)
te
=
time.time()
_basic_log(fn, result, args, kwargs)
print
" time = %.6f sec"
%
(te
-
ts)
print
" called_from_line : "
+
str
(get_line_number())
return
wrapper
if
loglevel
is
"debug"
:
return
debug_log_decorator
else
:
return
info_log_decorator
|
你可以看到两点,
1)我们分了两个log level,一个是info的,一个是debug的,然后我们在外尾根据不同的参数返回不同的decorator。
2)我们把info和debug中的相同的代码抽到了一个叫_basic_log的函数里,DRY原则。
一个MySQL的Decorator
下面这个decorator是我在工作中用到的代码,我简化了一下,把DB连接池的代码去掉了,这样能简单点,方便阅读。
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
52
53
54
55
56
57
58
|
import
umysql
from
functools
import
wraps
class
Configuraion:
def
__init__(
self
, env):
if
env
=
=
"Prod"
:
self
.host
=
"coolshell.cn"
self
.port
=
3306
self
.db
=
"coolshell"
self
.user
=
"coolshell"
self
.passwd
=
"fuckgfw"
elif
env
=
=
"Test"
:
self
.host
=
'localhost'
self
.port
=
3300
self
.user
=
'coolshell'
self
.db
=
'coolshell'
self
.passwd
=
'fuckgfw'
def
mysql(sql):
_conf
=
Configuraion(env
=
"Prod"
)
def
on_sql_error(err):
print
err
sys.exit(
-
1
)
def
handle_sql_result(rs):
if
rs.rows >
0
:
fieldnames
=
[f[
0
]
for
f
in
rs.fields]
return
[
dict
(
zip
(fieldnames, r))
for
r
in
rs.rows]
else
:
return
[]
def
decorator(fn):
@wraps
(fn)
def
wrapper(
*
args,
*
*
kwargs):
mysqlconn
=
umysql.Connection()
mysqlconn.settimeout(
5
)
mysqlconn.connect(_conf.host, _conf.port, _conf.user, \
_conf.passwd, _conf.db,
True
,
'utf8'
)
try
:
rs
=
mysqlconn.query(sql, {})
except
umysql.Error as e:
on_sql_error(e)
data
=
handle_sql_result(rs)
kwargs[
"data"
]
=
data
result
=
fn(
*
args,
*
*
kwargs)
mysqlconn.close()
return
result
return
wrapper
return
decorator
@mysql
(sql
=
"select * from coolshell"
)
def
get_coolshell(data):
... ...
... ..
|
线程异步
下面量个非常简单的异步执行的decorator,注意,异步处理并不简单,下面只是一个示例。
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
|
from
threading
import
Thread
from
functools
import
wraps
def
async(func):
@wraps
(func)
def
async_func(
*
args,
*
*
kwargs):
func_hl
=
Thread(target
=
func, args
=
args, kwargs
=
kwargs)
func_hl.start()
return
func_hl
return
async_func
if
__name__
=
=
'__main__'
:
from
time
import
sleep
@async
def
print_somedata():
print
'starting print_somedata'
sleep(
2
)
print
'print_somedata: 2 sec passed'
sleep(
2
)
print
'print_somedata: 2 sec passed'
sleep(
2
)
print
'finished print_somedata'
def
main():
print_somedata()
print
'back in main'
print_somedata()
print
'back in main'
main()
|