<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Decorator | 酷 壳 - CoolShell</title>
	<atom:link href="https://coolshell.cn/tag/decorator/feed" rel="self" type="application/rss+xml" />
	<link>https://coolshell.cn</link>
	<description>享受编程和技术所带来的快乐 - Coding Your Ambition</description>
	<lastBuildDate>Wed, 08 Jul 2020 09:38:17 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2</generator>
	<item>
		<title>Python修饰器的函数式编程</title>
		<link>https://coolshell.cn/articles/11265.html</link>
					<comments>https://coolshell.cn/articles/11265.html#comments</comments>
		
		<dc:creator><![CDATA[陈皓]]></dc:creator>
		<pubDate>Thu, 20 Mar 2014 01:50:34 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[程序设计]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[Decorator]]></category>
		<category><![CDATA[functional]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[函数式]]></category>
		<guid isPermaLink="false">http://coolshell.cn/?p=11265</guid>

					<description><![CDATA[<p>Python的修饰器的英文名叫Decorator，当你看到这个英文名的时候，你可能会把其跟Design Pattern里的Decorator搞混了，其实这是完全...</p>
<p class="read-more"><a class="btn btn-default" href="https://coolshell.cn/articles/11265.html"> Read More<span class="screen-reader-text">  Read More</span></a></p>
The post <a href="https://coolshell.cn/articles/11265.html">Python修饰器的函数式编程</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></description>
										<content:encoded><![CDATA[<p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415450859608158"
     crossorigin="anonymous"></script><img decoding="async" loading="lazy" class="alignright wp-image-11300" src="https://coolshell.cn/wp-content/uploads/2014/03/snake-hat-new-year-schedule-800x960.jpg" alt="" width="280" height="233" srcset="https://coolshell.cn/wp-content/uploads/2014/03/snake-hat-new-year-schedule-800x960.jpg 350w, https://coolshell.cn/wp-content/uploads/2014/03/snake-hat-new-year-schedule-800x960-300x249.jpg 300w, https://coolshell.cn/wp-content/uploads/2014/03/snake-hat-new-year-schedule-800x960-325x270.jpg 325w" sizes="(max-width: 280px) 100vw, 280px" />Python的修饰器的英文名叫Decorator，当你看到这个英文名的时候，你可能会把其跟Design Pattern里的Decorator搞混了，其实这是完全不同的两个东西。虽然好像，他们要干的事都很相似——都是想要对一个已有的模块做一些“修饰工作”，所谓修饰工作就是想给现有的模块加上一些小装饰（一些小功能，这些小功能可能好多模块都会用到），但又不让这个小装饰（小功能）侵入到原有的模块中的代码里去。但是OO的Decorator简直就是一场恶梦，不信你就去看看wikipedia上的词条（<a href="http://en.wikipedia.org/wiki/Decorator_pattern" target="_blank" rel="noopener noreferrer">Decorator Pattern</a>）里的UML图和那些代码，这就是我在《 <a title="链接：从面向对象的设计模式看软件设计" href="https://coolshell.cn/articles/8961.html" rel="bookmark">从面向对象的设计模式看软件设计</a>》“餐后甜点”一节中说的，OO鼓励了——“厚重地胶合和复杂层次”，也是《 <a title="链接：如此理解面向对象编程" href="https://coolshell.cn/articles/8745.html" rel="bookmark">如此理解面向对象编程</a>》中所说的“OO的狂热者们非常害怕处理数据”，Decorator Pattern搞出来的代码简直就是OO的反面教程。</p>
<p>Python 的 Decorator在使用上和Java/C#的Annotation很相似，就是在方法名前面加一个@XXX注解来为这个方法装饰一些东西。但是，Java/C#的Annotation也很让人望而却步，太TMD的复杂了，你要玩它，你需要了解一堆Annotation的类库文档，让人感觉就是在学另外一门语言。</p>
<p>而Python使用了一种相对于Decorator Pattern和Annotation来说非常优雅的方法，这种方法不需要你去掌握什么复杂的OO模型或是Annotation的各种类库规定，完全就是语言层面的玩法：一种函数式编程的技巧。如果你看过本站的《<a href="https://coolshell.cn/articles/10822.html">函数式编程</a>》，你一定会为函数式编程的那种“描述你想干什么，而不是描述你要怎么去实现”的编程方式感到畅快。（如果你不了解函数式编程，那在读本文之前，还请你移步去看看《<a href="https://coolshell.cn/articles/10822.html">函数式编程</a>》） 好了，我们先来点感性认识，看一个Python修饰器的Hello World的代码。</p>
<p><span id="more-11265"></span></p>
<h4>Hello World</h4>
<p>下面是代码（文件名：hello.py）：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="golang" data-enlighter-highlight="1-6,8">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()
</pre>
<p>当你运行代码，你会看到如下输出：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell">[chenaho@chenhao-air]$ python hello.py
hello, foo
i am foo
goodby, foo</pre>
<p>你可以看到如下的东西：</p>
<p style="padding-left: 30px;">1）函数foo前面有个@hello的“注解”，hello就是我们前面定义的函数hello</p>
<p style="padding-left: 30px;">2）在hello函数中，其需要一个fn的参数（这就用来做回调的函数）</p>
<p style="padding-left: 30px;">3）hello函数中返回了一个inner函数wrapper，这个wrapper函数回调了传进来的fn，并在回调前后加了两条语句。</p>
<h4>Decorator 的本质</h4>
<p>对于Python的这个@注解语法糖- Syntactic Sugar 来说，当你在用某个@decorator来修饰某个函数func时，如下所示:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">@decorator
def func():
    pass
</pre>
<p>其解释器会解释成下面这样的语句：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">func = decorator(func)</pre>
<p>尼玛，这不就是把一个函数当参数传到另一个函数中，然后再回调吗？是的，但是，我们需要注意，那里还有一个赋值语句，把decorator这个函数的返回值赋值回了原来的func。 根据《<a href="https://coolshell.cn/articles/10822.html" target="_blank" rel="noopener noreferrer">函数式编程</a>》中的<strong>first class functions</strong>中的定义的，你可以把函数当成变量来使用，所以，decorator必需得返回了一个函数出来给func，这就是所谓的<strong>higher order function </strong>高阶函数，不然，后面当func()调用的时候就会出错。 就我们上面那个hello.py里的例子来说，</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">@hello
def foo():
    print "i am foo"
</pre>
<p>被解释成了：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python"> foo = hello(foo)</pre>
<p><strong>是的，这是一条语句，而且还被执行了。</strong>你如果不信的话，你可以写这样的程序来试试看：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">def fuck(fn):
    print "fuck %s!" % fn.__name__[::-1].upper()

@fuck
def wfg():
    pass
</pre>
<p>没了，就上面这段代码，没有调用wfg()的语句，你会发现， fuck函数被调用了，而且还很NB地输出了我们每个人的心声！</p>
<p>再回到我们hello.py的那个例子，我们可以看到，<strong>hello(foo)返回了wrapper()函数，所以，foo其实变成了wrapper的一个变量，而后面的foo()执行其实变成了wrapper()</strong>。</p>
<p>知道这点本质，当你看到有多个decorator或是带参数的decorator，你也就不会害怕了。</p>
<p>比如：多个decorator</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">@decorator_one
@decorator_two
def func():
    pass</pre>
<p>相当于：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">func = decorator_one(decorator_two(func))</pre>
<p>比如：带参数的decorator：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">@decorator(arg1, arg2)
def func():
    pass</pre>
<p>相当于：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">func = decorator(arg1,arg2)(func)</pre>
<p>这意味着decorator(arg1, arg2)这个函数需要返回一个“真正的decorator”。</p>
<h4>带参数及多个Decrorator</h4>
<p>我们来看一个有点意义的例子（文件名：html.py）：</p>
<p>在上面这个例子中，我们可以看到：makeHtmlTag有两个参数。所以，<strong>为了让 <span style="color: #000080;">hello = makeHtmlTag(arg1, arg2)(hello)</span> 成功，makeHtmlTag 必需返回一个decorator</strong>（这就是为什么我们在makeHtmlTag中加入了real_decorator()的原因）<strong>，这样一来，我们就可以进入到 decorator 的逻辑中去了</strong>—— decorator得返回一个wrapper，wrapper里回调hello。<strong>看似那个makeHtmlTag() 写得层层叠叠，但是，已经了解了本质的我们觉得写得很自然</strong>。 你看，Python的Decorator就是这么简单，没有什么复杂的东西，你也不需要了解过多的东西，使用起来就是那么自然、体贴、干爽、透气，独有的速效凹道和完美的吸收轨迹，让你再也不用为每个月的那几天感到焦虑和不安，再加上贴心的护翼设计，量多也不用当心。对不起，我调皮了。 什么，你觉得上面那个带参数的Decorator的函数嵌套太多了，你受不了。好吧，没事，我们看看下面的方法。</p>
<h4>class式的 Decorator</h4>
<p>首先，先得说一下，decorator的class方式，还是看个示例：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-highlight="3,7">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__()</pre>
<p>上面这个示例展示了，用类的方式声明一个decorator。我们可以看到这个类中有两个成员：<br />
1）一个是<strong>init</strong>()，这个方法是在我们给某个函数decorator时被调用，所以，需要有一个fn的参数，也就是被decorator的函数。<br />
2）一个是<strong>call</strong>()，这个方法是在我们调用被decorator函数时被调用的。<br />
上面输出可以看到整个程序的执行顺序。</p>
<p>这看上去要比“函数式”的方式更易读一些。</p>
<p>下面，我们来看看用类的方式来重写上面的html.py的代码（文件名：html.py）：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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 "&lt;" + self._tag + self._css_class+"&gt;"  \
                       + fn(*args, **kwargs) + "&lt;/" + self._tag + "&gt;"
        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")
</pre>
<p>上面这段代码中，我们需要注意这几点：<br />
1）如果decorator有参数的话，<strong>init</strong>() 成员就不能传入fn了，而fn是在<strong>call</strong>的时候传入的。<br />
2）这段代码还展示了 wrapped(*args, **kwargs) 这种方式来传递被decorator函数的参数。（其中：args是一个参数列表，kwargs是参数dict，具体的细节，请参考Python的文档或是<a href="http://stackoverflow.com/questions/3394835/args-and-kwargs" target="_blank" rel="noopener noreferrer">StackOverflow的这个问题</a>，这里就不展开了）</p>
<h4>用Decorator设置函数的调用参数</h4>
<p>你有三种方法可以干这个事：</p>
<p>第一种，通过 **kwargs，这种方法decorator会在kwargs中注入参数。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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()</pre>
<p>第二种，约定好参数，直接修改参数</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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()</pre>
<p>第三种，通过 *args 注入</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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()</pre>
<h4>Decorator的副作用</h4>
<p>到这里，我相信你应该了解了整个Python的decorator的原理了。</p>
<p>相信你也会发现，被decorator的函数其实已经是另外一个函数了，对于最前面那个hello.py的例子来说，如果你查询一下foo.<strong>name</strong>的话，你会发现其输出的是“wrapper”，而不是我们期望的“foo”，这会给我们的程序埋一些坑。所以，Python的functool包中提供了一个叫wrap的decorator来消除这样的副作用。下面是我们新版本的 hello.py。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-highlight="1,3">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
</pre>
<p>当然，即使是你用了functools的wraps，也不能完全消除这样的副作用。</p>
<p>来看下面这个示例：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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: []</pre>
<p>你会发现，即使是你你用了functools的wraps，你在用getargspec时，参数也不见了。</p>
<p>要修正这一问，我们还得用Python的反射来解决，下面是相关的代码：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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)</pre>
<p>当然，我相信大多数人的程序都不会去getargspec。所以，用functools的wraps应该够用了。</p>
<h4>一些decorator的示例</h4>
<p>好了，现在我们来看一下各种decorator的例子：</p>
<h5>给函数调用做缓存</h5>
<p>这个例实在是太经典了，整个网上都用这个例子做decorator的经典范例，因为太经典了，所以，我这篇文章也不能免俗。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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 &lt; 2:
        return n
    return fib(n - 1) + fib(n - 2)
</pre>
<p>上面这个例子中，是一个斐波拉契数例的递归算法。我们知道，这个递归是相当没有效率的，因为会重复调用。比如：我们要计算fib(5)，于是其分解成fib(4) + fib(3)，而fib(4)分解成fib(3)+fib(2)，fib(3)又分解成fib(2)+fib(1)…… 你可看到，基本上来说，fib(3), fib(2), fib(1)在整个递归过程中被调用了两次。</p>
<p>而我们用decorator，在调用函数前查询一下缓存，如果没有才调用了，有了就从缓存中返回值。一下子，这个递归从二叉树式的递归成了线性的递归。</p>
<h5>Profiler的例子</h5>
<p>这个例子没什么高深的，就是实用一些。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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

</pre>
<h5>注册回调函数</h5>
<p>下面这个示例展示了通过URL的路由来调用相关注册的函数示例：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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')
</pre>
<p>注意：<br />
1）上面这个示例中，用类的实例来做decorator。<br />
2）decorator类中没有<strong>call</strong>()，但是wrapper返回了原函数。所以，原函数没有发生任何变化。</p>
<h5>给函数打日志</h5>
<p>下面这个示例演示了一个logger的decorator，这个decorator输出了函数名，参数，返回值，和运行时间。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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)</pre>
<p>上面那个打日志还是有点粗糙，让我们看一个更好一点的（带log level参数的）：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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</pre>
<p>但是，上面这个带log level参数的有两具不好的地方，<br />
1） loglevel不是debug的时候，还是要计算函数调用的时间。<br />
2） 不同level的要写在一起，不易读。</p>
<p>我们再接着改进：</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">import 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
</pre>
<p>你可以看到两点，<br />
1）我们分了两个log level，一个是info的，一个是debug的，然后我们在外尾根据不同的参数返回不同的decorator。<br />
2）我们把info和debug中的相同的代码抽到了一个叫_basic_log的函数里，DRY原则。</p>
<h5>一个MySQL的Decorator</h5>
<p>下面这个decorator是我在工作中用到的代码，我简化了一下，把DB连接池的代码去掉了，这样能简单点，方便阅读。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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 &gt; 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):
    ... ...
    ... ..
</pre>
<h5>线程异步</h5>
<p>下面量个非常简单的异步执行的decorator，注意，异步处理并不简单，下面只是一个示例。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python">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()
</pre>
<h4>其它</h4>
<p>关于更多的示例，你可以参看： <a href="https://wiki.python.org/moin/PythonDecoratorLibrary" target="_blank" rel="noopener noreferrer">Python Decorator Library</a></p>
<p>关于Python Decroator的各种提案，可以参看：<a href="https://wiki.python.org/moin/PythonDecoratorProposals" target="_blank" rel="noopener noreferrer">Python Decorator Proposals</a></p>
<p>（全文完）<!--



<p align="center"><a href= target=_blank><img decoding="async" src=""></a></p>





<p align="center"><img decoding="async" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.weixin.jpg"> <img decoding="async" loading="lazy" src="https://coolshell.cn/wp-content/uploads/2020/03/coolshell.mini_.jpg" width="300" height="300"> <br />关注CoolShell微信公众账号和微信小程序</p>

 

--></p>
<div style="margin-top: 15px; font-size: 16px;color: #cc0000;">
<p align="center"><strong>（转载本站文章请注明作者和出处 <a href="https://coolshell.cn/">酷 壳 &#8211; CoolShell</a> ，请勿用于任何商业用途）</strong></p>
</div>

<div class="wp_rp_wrap  wp_rp_vertical_m" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">相关文章</h3><ul class="related_post wp_rp"><li ><a href="https://coolshell.cn/articles/17929.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2017/06/go-hardhat-150x150.png" alt="Go编程模式：修饰器" width="150" height="150" /></a><a href="https://coolshell.cn/articles/17929.html" class="wp_rp_title">Go编程模式：修饰器</a></li><li ><a href="https://coolshell.cn/articles/10822.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2013/12/yoda-lambda-150x150.png" alt="函数式编程" width="150" height="150" /></a><a href="https://coolshell.cn/articles/10822.html" class="wp_rp_title">函数式编程</a></li><li ><a href="https://coolshell.cn/articles/21164.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/12/go.map_.reduce-150x150.png" alt="Go编程模式：Map-Reduce" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21164.html" class="wp_rp_title">Go编程模式：Map-Reduce</a></li><li ><a href="https://coolshell.cn/articles/21146.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2020/12/go.options-150x150.png" alt="Go 编程模式：Functional Options" width="150" height="150" /></a><a href="https://coolshell.cn/articles/21146.html" class="wp_rp_title">Go 编程模式：Functional Options</a></li><li ><a href="https://coolshell.cn/articles/19612.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2019/07/1920px-Margaret_Hamilton_-_restoration-e1563697198766-1-150x150.jpg" alt="50年前的登月程序和程序员有多硬核" width="150" height="150" /></a><a href="https://coolshell.cn/articles/19612.html" class="wp_rp_title">50年前的登月程序和程序员有多硬核</a></li><li ><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_thumbnail"><img src="https://coolshell.cn/wp-content/uploads/2018/05/300x262-150x150.jpg" alt="程序员练级攻略（2018)  与我的专栏" width="150" height="150" /></a><a href="https://coolshell.cn/articles/18360.html" class="wp_rp_title">程序员练级攻略（2018)  与我的专栏</a></li></ul></div></div>The post <a href="https://coolshell.cn/articles/11265.html">Python修饰器的函数式编程</a> first appeared on <a href="https://coolshell.cn">酷 壳 - CoolShell</a>.]]></content:encoded>
					
					<wfw:commentRss>https://coolshell.cn/articles/11265.html/feed</wfw:commentRss>
			<slash:comments>84</slash:comments>
		
		
			</item>
	</channel>
</rss>
