Python装饰器学习

在《Core Python Programming 2nd》中学习到了装饰器,这对我来说是个完全陌生的语法,第一遍愣是没看懂,很有必要记一下。

 

第一眼看到这个词Decorator,我联想到了DP中的Decorator模式,后来才知道完全不是这么一回事。(再次鄙视一下国内浮躁的博客,我google了一下,几乎千篇一律都是什么锁同步装饰器、超时装饰器,我对原作者表达敬仰,可是大家都是转载就不像话了,也是对网络资源的极大浪费,也许真正有价值的博文就湮没在这片都是一模一样的东西里了)

 

1. 这是个什么东东?
书上说得不是太清楚,它说类似于Java的AOP(Aspect Oriented Programming,面向方面编程),我对AOP一无所知。根据我对许多例子用法的反复揣摩,我认为是类似于程序设计语义学中所说的前键后键 的概念(Eiffel中的@pre@post )。当然你可以在装饰器中做比前键与后键更多的事,如:引入日志、增加计时逻辑来检测性能、给函数增加事务的能力。

 

其实总体说起来,装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。

 

2. 装饰器语法

(1)无参数装饰器

  1. def deco(func):  
  2.     print func  
  3.     return func  
  4. @deco  
  5. def foo():pass  
  6. foo()  
def deco(func): print func return func @deco def foo():pass foo()

第一个函数deco是装饰函数,它的参数就是被装饰的函数对象。我们可以在deco函数内对传入的函数对象做一番“装饰”,然后返回这个对象(记住一定要返回 ,不然外面调用foo的地方将会无函数可用。实际上此时foo=deco(foo))

 

我写了个小例子,检查函数有没有说明文档:

  1. def deco_functionNeedDoc(func):  
  2.     if func.__doc__ == None :  
  3.         print func, "has no __doc__, it's a bad habit."  
  4.     else:  
  5.         print func, ':', func.__doc__, '.'  
  6.     return func  
  7. @deco_functionNeedDoc  
  8. def f():  
  9.     print 'f() Do something' 
  10. @deco_functionNeedDoc  
  11. def g():  
  12.     'I have a __doc__'  
  13.     print 'g() Do something'  
  14. f()  
  15. g()  
def deco_functionNeedDoc(func): if func.__doc__ == None : print func, "has no __doc__, it's a bad habit." else: print func, ':', func.__doc__, '.' return func @deco_functionNeedDoc def f(): print 'f() Do something' @deco_functionNeedDoc def g(): 'I have a __doc__' print 'g() Do something' f() g()

 

(2)有参数装饰器

  1. def decomaker(arg):  
  2.     '通常对arg会有一定的要求'  
  3.     """由于有参数的decorator函数在调用时只会使用应用时的参数  
  4.        而不接收被装饰的函数做为参数,所以必须在其内部再创建  
  5.        一个函数  
  6.     """  
  7.     def newDeco(func):    #定义一个新的decorator函数  
  8.         print func, arg  
  9.         return func  
  10.     return newDeco  
  11. @decomaker(deco_args)  
  12. def foo():pass  
  13. foo()  
def decomaker(arg): '通常对arg会有一定的要求' """由于有参数的decorator函数在调用时只会使用应用时的参数 而不接收被装饰的函数做为参数,所以必须在其内部再创建 一个函数 """ def newDeco(func): #定义一个新的decorator函数 print func, arg return func return newDeco @decomaker(deco_args) def foo():pass foo()

第一个函数decomaker是装饰函数,它的参数是用来加强“加强装饰”的。由于此函数并非被装饰的函数对象,所以在内部必须至少创建一个接受被装饰函数的函数,然后返回这个对象(实际上此时foo=decomaker(arg)(foo))

 

这个我还真想不出什么好例子,还是见识少啊,只好借用同步锁的例子了:

  1. def synchronized(lock):  
  2.     """锁同步装饰方法 
  3.     !lock必须实现了acquire和release方法 
  4.     """  
  5.     def sync_with_lock(func):  
  6.         def new_func(*args, **kwargs):  
  7.             lock.acquire()  
  8.             try:  
  9.                 return func(*args, **kwargs)  
  10.             finally:  
  11.                 lock.release()  
  12.         new_func.func_name = func.func_name  
  13.         new_func.__doc__ = func.__doc__  
  14.         return new_func  
  15.     return sync_with_lock  
  16. @synchronized(__locker)  
  17. def update(data):  
  18. """更新计划任务"""  
  19.     tasks = self.get_tasks()  
  20.     delete_task = None  
  21.     for task in tasks:  
  22.         if task[PLANTASK.ID] == data[PLANTASK.ID]:  
  23.             tasks.insert(tasks.index(task), data)  
  24.             tasks.remove(task)  
  25.             delete_task = task  
  26.     r, msg = self._refresh(tasks, delete_task)  
  27.     return r, msg, data[PLANTASK.ID]  
def synchronized(lock): """锁同步装饰方法 !lock必须实现了acquire和release方法 """ def sync_with_lock(func): def new_func(*args, **kwargs): lock.acquire() try: return func(*args, **kwargs) finally: lock.release() new_func.func_name = func.func_name new_func.__doc__ = func.__doc__ return new_func return sync_with_lock @synchronized(__locker) def update(data): """更新计划任务""" tasks = self.get_tasks() delete_task = None for task in tasks: if task[PLANTASK.ID] == data[PLANTASK.ID]: tasks.insert(tasks.index(task), data) tasks.remove(task) delete_task = task r, msg = self._refresh(tasks, delete_task) return r, msg, data[PLANTASK.ID]

调用时还是updae(data)。

 

同时还可以将多个装饰器组合 使用:

  1. @synchronized(__locker)  
  2. @deco_functionNeedDoc  
  3. def f():  
  4.     print 'f() Do something'  
@synchronized(__locker) @deco_functionNeedDoc def f(): print 'f() Do something'

学后的总是感觉就是:装饰器可以让函数轻装上阵,更重要的是将函数的约束放置于接口处,使意图更加明了,同时又不增加调用者的负担。

上一篇:Python自学之路—变量与运算


下一篇:详解生成器、迭代器