Python Decorator Closure

http://www.cnblogs.com/tqsummer/archive/2011/01/24/1943314.html, Python和Decorator(装饰器)模式

http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html, Python装饰器与面向切面编程

最近在看FP相关, 看到Closure, 想起这个... python的装饰器方法是用闭包实现的

Closure是什么就不解释了, 可以看上面第一个blog

 

装饰器, 经典的设计模式, 动态地给一个对象添加一些额外的职责.

大家在写代码的时候, 除了核心的逻辑, 往往还有许多辅助的逻辑, 比如, log, try catch, lock, time计时, 等等...

如果都混在一起, 严重影响代码的整洁度, 比如log或try catch这种需要随处加的, 非常影响开发效率, 和可读性

而装饰器最大的应用, 就是将核心代码和辅助代码分离.

 

以time为例,大家在测performance的时候会在自己代码里面加上大量的这样的代码, 非常烦...

import time
def foo():
    start = time.clock()
    print 'in foo()'
    end = time.clock()
    print 'used:', end - start
 

Python这种动态语言, function也是first-class, 所以简单改进如下, 虽然简单, 但是这已经属于装饰器设计模式
这种改动的问题在于, 你想想这种performance代码都是临时加上的, 如果每次都需要修改函数名来测时间, 相当麻烦

import time
 
def foo():
    print 'in foo()'
 
def timeit(func):
    start = time.clock()
    func()
    end =time.clock()
    print 'used:', end - start
 
这个例子开始, 就是使用闭包(closure)来实现装饰器模式. 其中wrapper就是个闭包, 因为里面包含外部变量func
好处是, 在每个需要test的function前面, 加上一个声明就ok, 更方便一些.
有个问题需要注意的是, 完成foo = timeit(foo)后, foo的funciton name是wrapper, 而不是foo. 如果要解决这个问题, 需要使用functools.wraps
import time
 
def foo():
    print 'in foo()'
 
def timeit(func):
     def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    return wrapper
 
foo = timeit(foo)
foo()

 

装饰器方法的Python语法糖,@

@timeit,在定义上加上这一行与另外写foo = timeit(foo)完全等价

import time
 
def timeit(func):
    def wrapper():
        start = time.clock()
        func()
        end =time.clock()
        print 'used:', end - start
    return wrapper
 
@timeit
def foo():
    print 'in foo()'

python中内嵌的装饰器方法, 分别是staticmethod、classmethod和property
 
 
再给出一个lock的例子, 对于线程lock需要传入同一个lock对象, 更加体现出闭包
博主嫌这个方法不够优雅, 写了套更简单的
把lock对象的生成封装到一个Decorate类中, 并在类初始化是完成对于所有类函数自动的wrapper, 这个取决于python的动态特性, 可以run-time时获取, 修改函数的逻辑.
具体可以参考第一个blog
def sync(func):
    def   wrapper(*args, **kv):
          self = args[0]
          self.lock.acquire()
          try:
               return func(*args, **kv)
          finally:
               self.lock.release()
    return wrapper

class Foo(object):
       def __init__(self, …):
              self.lock = threading.Lock()
       @sync
       def  interface1(self, …):
              do something

       @sync
       def  interface2(self, …):
              do something

 
 
 
 
 
 
 
 
 

posted on 2013-02-08 15:49  fxjwind  阅读(459)  评论(0编辑  收藏  举报