Python之美--Decorator深入详解(一) Python Decorators(二):Decorator参数 Python Decorator初体验

https://www.cnblogs.com/zh605929205/p/7704902.html

由于没时间编写,就把几张写的不错的文章摘录整合到一起。原文地址: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()

猜你喜欢

转载自blog.csdn.net/hshl1214/article/details/80284481
今日推荐