Love me little, love me long.

Search Result For:
No Results Found...

Sorry, but nothing matched your search terms. Please try again with some different keywords.

Python Decorator

Nov 24, 2014

python decorator 大概是每个pythoner比看到内容吧.顾名思义:“装饰器”,绝对是把什么什么东西通过另外的东西修饰了一番。

####先来看下最基本的显而易见的例子吧:

        def log(func):
            def wrapper(*args, **kw):
                print 'call %s():' % func.__name__
                func(*args, **kw)---
            return wrapper

        @log
        def now():
            print '2013-12-25'

        now()

@log就是所谓的语法糖,从上例最终的表现形式就是:将now()函数传给了方法log..最终调用是 调用了内部函数wrapper..

接下来一步步刨析:
log函数内部有个wrapper函数,这样就形成了一个闭包wrapper,这个函数对于其他部分是一个独立的模块,但其可以使用log的参数也就是传进来的方法func,func在log内部是相当于warpper是全局变量(log 内部的作用域)经过wrapper的处理后,now函数就不再是单单输出“2013-12-25”了。所以也验证了前面所说的经过某某修饰成为了另外的某某某。相当于now = log(now())

如果前面的例子打印now.__name__,结果为:wrapper 而不是now

为了解决这个问题,需要如下操作:

    from functools import wraps
    def log(func):
    	@wraps(func)
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            func(*args, **kw)---
        return wrapper

如果now 函数需要传参数的话需要反射来处理,具体可看http://coolshell.cn/articles/11265.html

####以上是一个最基本的decorator 应用,接下来说明在使用decorator时传参

    from functools import wraps
    def log(args1,args2):
        def real_decorator(func):
            @wraps(func)
            def wrapper(*args, **kw):
                print 'call %s():' % func.__name__
                func(args1, args1,args)
            return wrapper
        return real_decorator

    @log("log pass paramter1 to log","log pass paramter2 to log")
    def now(*args):
        print args
        print '2013-12-25'

    now("now pass parameter to wrapper")
    print now.__name__
    
result :
>call now():
>('log pass paramter1 to log', 'log pass paramter1 to log', ('now pass parameter to wrapper',))  
>2013-12-25  
>now

说明对于需要使用语法糖 传参的时候需要返回一个函数real_decorator,再在内部定义具体调用的函数wrapper这里相当于:log("log pass paramter1 to log","log pass paramter2 to log")((now())

####使用多个decorator:

    from functools import wraps
    def log(args1,args2):
        def real_decorator(func):
            @wraps(func)
            def wrapper(*args, **kw):
                print 'call %s():' % func.__name__
                func(args1, args1,args)
            return wrapper
        return real_decorator

    def another_log(func):
        def wrapper(pams):
            print "another wrapper of %s():\n" % func.__name__+pams
        return wrapper
    
    @another_log
    @log("log pass paramter1 to log","log pass paramter2 to log")
    def now(*args):
        print args
        print '2013-12-25'

    now("now pass parameter to wrapper")
    print now.__name__
    
results:  
>another wrapper of now():  
>now pass parameter to wrapper  
>wrapper

说明:结果是 输出了 another_log 的内容,那么它是将log decrator 过后的方法再次 decorator,即如下形式:another_log(log(param1,param2)(now)),也就是两层包装

####类式的 Decorator

    class TestDecorator(object):

        def __init__(self,func):
            self.decorator_fn = func
        def __call__(self):
            print self.decorator_fn.__name__
            self.decorator_fn()
            print "inside myDecorator.__call__()"
    @TestDecorator        
    def now():
        print "2014-01-01"

    now()

基本的实例如上,在这个类中必须要有__call__方法,而所有关于修饰的内容都应当从__call__方法里面去定义

输出:

now
2014-01-01
inside class call()

一个好的完整例子:

    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返回了原函数。所以,原函数没有发生任何变化。

更多例子:https://wiki.python.org/moin/PythonDecoratorLibrary