python装饰器 - ZhangMaozheng/Python GitHub Wiki

装饰器@decorator

作用:可以极大地简化代码,避免每个函数编写重复性代码。

def f1(x):
  return x*2
def new_fn(f):
  def fn(x):
    print 'call' + f.__name__ + '()'
    return f(x)
  return fn

使用方法1:

g1 = new_fn(f1)
print g1(5)

使用方法2:

f1 = new_fn(f1) # f1的原始定义函数被彻底隐藏
print f1(5)

Python内置的@语法就是为了简化装饰器调用

@new_fn                                 def f1(x):
def f1(x):               =>               return x*2
  return x*2                            f1 = new_fn(f1)

有时需要让装饰器自适应任何参数定义的函数,可以利用Python的*args和**kw,保证任意个数的参数总是能正常调用。

编写带有参数的decorator

def log(prefix):
  def log_decorator(f):
    def wrapper(*args, **kw):
      print '[%s] %s()...' % (prefix, f.__name__)
      return f(*args, **kw)
    return wrapper
  return log_decorator

@log('DEBUG')
def test():
  pass
print test()

[DEBUG] test()...
None

python中decorator的完善

def log(f):
  def wrapper(*args, **kw):
    print 'call...'
    return f(*args, **kw)
  return wrapper
@log
def f2(x):
  pass
print f2.__name__
wrapper

如果f2是普通函数,一定输出f2,由于decorator返回的新函数的函数名已经不是'f2',而是@log内部定义的'wrapper'。这对于那些依赖函数名的代码就会失效。decorator还改变了函数的__doc__等其它属性。解决这样问题的办法除了把原函数的一些属性一个个复制到新函数中,就用Pyhont内置的functools。

import functools
def log(f):
  @functools.wraps(f)
  def wrapper(*args, **kw):
    print 'call...'
    return f(*args, **kw)
  return wrapper