您的位置:首页 > 编程语言 > Python开发

python decorator 基础

2017-01-11 21:24 381 查看
  一般来说,装饰器是一个函数,接受一个函数(或者类)作为参数,返回值也是也是一个函数(或者类)。首先来看一个简单的例子:
  

def log_cost_time(stream):
def inner_dec(func):
def wrapped(*args, **kwargs):
import time
begin = time.time()
try:
return func(*args, **kwargs)
finally:
stream.write('func %s cost %s \n' % (func.__name__, time.time() - begin))
return wrapped
return inner_dec

import sys
@log_cost_time(sys.stdout)
def complex_func(num):
ret = 0
for i in xrange(num):
ret += i * i
return ret

if __name__ == '__main__':
print complex_func(100000)


code snippet 1

  log_cost_time函数也接受一个参数,该参数用来指定信息的输出流,对于带参数的decorator
  @dec(dec_args)
  def func(*args, **kwargs):pass
  等价于 func = dec(dec_args)(*args, **kwargs)。

  装饰器对类的修饰也是很简单的,只不过平时用得不是很多。举个例子,我们需要给修改类的__str__方法,代码很简单。
  

def Haha(clz):
clz.__str__ = lambda s: "Haha"
return clz

@Haha
class Widget(object):
''' class Widget '''

if __name__ == '__main__':
w = Widget()
print w


  那什么场景下有必要使用decorator呢,设计模式中有一个模式也叫装饰器。我们先简单回顾一下设计模式中的装饰器模式,简单的一句话概述

  动态地为某个对象增加额外的责任





  由于装饰器模式仅从外部改变组件,因此组件无需对它的装饰有任何了解;也就是说,这些装饰对该组件是透明的。

  下图来自《设计模式Java手册》或者GOF的《设计模式》
  




  回到Python中来,用decorator语法实现装饰器模式是很自然的,比如文中的示例代码,在不改变被装饰对象的同时增加了记录函数执行时间的额外功能。当然,由于Python语言的灵活性,decorator是可以修改被装饰的对象的(比如装饰类的例子)。decorator在python中用途非常广泛,下面列举几个方面:
  (1)修改被装饰对象的属性或者行为
  (2)处理被函数对象执行的上下文,比如设置环境变量,加log之类
  (3)处理重复的逻辑,比如有N个函数都可能跑出异常,但是我们不关心这些异常,只要不向调用者传递异常就行了,这个时候可以写一个catchall的decorator,作用于所用可能跑出异常的函数

def catchall(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
pass
return wrapped


  (4)框架代码,如flask, bottle等等,让使用者很方便就能使用框架,本质上也避免了重复代码。

  decorator的奇妙应用往往超出相应,经常在各种源码中看到各种神奇的用法,酷壳这篇文章举的例子也不错。

references
pep 0318:https://www.python.org/dev/peps/pep-0318/#syntax-alternatives
PYTHON修饰器的函数式编程:http://coolshell.cn/articles/11265.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: