Chinaunix首页 | 论坛 | 博客
  • 博客访问: 38266
  • 博文数量: 12
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 79
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-07 21:35
文章分类

全部博文(12)

文章存档

2015年(12)

我的朋友

分类: Python/Ruby

2015-01-29 18:35:44

原文地址:python 装饰器 作者:yueming

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

(1)无参数装饰器

  1. def deco(func):
  2.     print func
  3.     return func
  4. @deco
  5. def foo():pass
  6. 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()
(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()

第一个函数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]

调用时还是updae(data)

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


  1. @synchronized(__locker)
  2. @deco_functionNeedDoc
  3. def f():
  4.     print 'f() Do something'
装饰器可以让函数轻装上阵,更重要的是将函数的约束放置于接口处,使意图更加明了,同时又不增加调用者的负担。

以上内容原文链接

----------------------------------------------------------------------------------------------------------
所谓装饰器仅仅是一种语法糖, 可作用的对象可以是函数也可以是类, 装饰器本身是一个函数, 其主要工作方式就是将被装饰的类或者函数当作参数传递给装饰器函数, 比如定义如下装饰器

  1. import time

  2. def run_time(func):
  3.     def wrapper(*args, **kwargs):
  4.         start = time.time()
  5.         r = func(*args, **kwargs)
  6.         print time.time() - start
  7.         return r
  8.     return wrapper
我们用这个装饰器装饰一个test函数

  1. @run_time
  2. def test():
  3.     print "just a test"
前面说过其实装饰器就是一个语法糖, 就是将被装饰的函数作为参数传递给装饰器函数, 所以上面可以展开为

  1. test = run_time(test)

装饰器将在解释器运行一开始就被加载, 从而将被装饰的函数将被展开成如上方式, 因为 run_time装饰器返回wrapper函数, 所以当调用test函数时其实就是对wrapper的调用
如果你在Python shell下执行以上语句就会发现定义完test函数然后查看test时, shell所展示的是wrapper函数: 



接下来说说如何编写带参数的装饰器, 大家如果细心的话就可以发现其实带参数的装饰器是经过调用"装饰器"函数返回的一个装饰器, 之所以装饰器上打引号是说明其实这个所谓的"装饰器"只不过是一个普通的函数, 但这个普通的函数返回一个装饰器, 可以参看下面例子:

  1. import time

  2. def route(url):
  3.     def decorator(func):
  4.         func.__url__ = url
  5.         return func
  6.     return decorator

  7. @route(r"/")
  8. def index():
  9.     return "Hi"
大家可以发现在使用route装饰器时我们其实是调用了route函数, route函数返回一个decorator装饰器, 因为我们不需要在装饰器内运行函数, 所以不需要一个wrapper函数来收集参数.














阅读(1011) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~