Python有很多漂亮的特性,decorator就是其中之一。什么是decorator?其他语言里面也有类似于decorator的东西,那就是宏。但是c里面的宏的用法是有点诡异的,Bruce Eckel都说,c里面的宏完全是另外一种语言[1](不能同意更多了,从好多#define都会被当做面试题就可以看出来了:D)。
废话少说,先上一个decorator过把瘾。
def new_f(*args, **kwargs):
print 'enter new_f'
return f(*args, **kwargs)
return new_f
@my_decorator
def f(a, b):
return a + b
上面的my_decorator只是在调用f之前打印“Enter new_f”出来,然后再返回f的结果。想要达到同样的目的,更普通一点的做法是:
return a + b
f = my_decorator(f)
你会选择普通点的做法,还是文艺点的@my_decorator呢?
用类做decorator
上面的例子用函数作decorator,类也是可以的,只要类实现了__call__方法。其实用类做decorator是更普遍的做法。
def __init__(self, f):
print '__init__()'
self.f = f
def __call__(self):
print '__call__'
self.f()
用Decorator类修饰函数试下:
... def f():
... print "in f()"
...
__init__()
>>> f()
__call__
in f()
与前面的函数做decorator不同的是,用Decorator类修饰f()时产生了一句输出。其实这也很容易理解,因为python的函数本身也是对象,只是我们无法定义函数初始化时候的操作罢了。类就不同了,我们可以随意定义__init__函数来实现想要的功能。
带参数的decorator
decorator也可以有自己的参数,比如:
def f(....)
上面的等效于
f = temp(f)
带参数的decorator和不带参数的其实是有很大不同的。不相信?那自己写一个函数实现的decorator,再同下面这个做下对比:
def wrap(f):
def wrapped_f(*args):
print message
return f(*args)
return wrapped_f
return wrap
@decorate('message')
def f(a, b):
print 'add a and b'
return a + b
猜你的反应肯定是:“WTF!怎么会有这么多层函数!”。先别急,把最外面的一层函数去掉,不就是最简单的没有参数的decorator了吗?其实wrap只是在decoration阶段接收message参数,wrapped_f才是真正会调用的函数。
用类实现的就是下面这个样子的了:
def __init__(self, message):
self.message = message
def __call__(self, f):
def wrapped_f(*args):
print self.message
return f(*args)
return wrapped_f
Real word decorators
理解decorator的基础之后,再看几个例子。
我们都知道c++的类可以有static方法,这类方法并不属于某一个具体的实例,而是存在于整个类的命名范围之内的。所有的实例都共用这个方法。在python中,我们也可以实现。方法就是是借助@staticmethod这个decorator:
@staticmethod
def add(x,y):
return x + y
x = Foo.add(3,4)
另外一个常见的decorator就是@classmethod。用classmethod修饰的方法和普通的方法不同,普通的方法第一个参数都是self,而classmethod的第一个参数则是类。例如:
factor = 1
@classmethod
def mul(cls,x):
return cls.factor*x
class TwoTimes(Times):
factor = 2
x = TwoTimes.mul(4)
还有更多的用法,参见这里。

