Python Decorator

Python有很多漂亮的特性,decorator就是其中之一。什么是decorator?其他语言里面也有类似于decorator的东西,那就是宏。但是c里面的宏的用法是有点诡异的,Bruce Eckel都说,c里面的宏完全是另外一种语言[1]不能同意更多了,从好多#define都会被当做面试题就可以看出来了:D)。

废话少说,先上一个decorator过把瘾。

[ccb_python]
def my_decorator(f):

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
[/ccb_python]

上面的my_decorator只是在调用f之前打印“Enter new_f”出来,然后再返回f的结果。想要达到同样的目的,更普通一点的做法是:

[ccb_python]
def f(a, b):
return a + b

f = my_decorator(f)
[/ccb_python]
你会选择普通点的做法,还是文艺点的[ccib_python]@my_decorator[/ccib_python]呢?

用类做decorator

上面的例子用函数作decorator,类也是可以的,只要类实现了[ccib_python]__call__[/ccib_python]方法。其实用类做decorator是更普遍的做法。

[ccb_python]
class Decorator(object):

def __init__(self, f):
print ‘__init__()’
self.f = f

def __call__(self):
print ‘__call__’
self.f()
[/ccb_python]

用Decorator类修饰函数试下:

[ccb_python]
>>> @Decorator
… def f():
… print “in f()”

__init__()
>>> f()
__call__
in f()
[/ccb_python]
与前面的函数做decorator不同的是,用Decorator类修饰f()时产生了一句输出。其实这也很容易理解,因为python的函数本身也是对象,只是我们无法定义函数初始化时候的操作罢了。类就不同了,我们可以随意定义[ccib_python]__init__[/ccib_python]函数来实现想要的功能。

带参数的decorator

decorator也可以有自己的参数,比如:

[ccb_python]
@decorate(message)
def f(….)
[/ccb_python]

上面的等效于

[ccb_python]
temp = decorate(message)
f = temp(f)
[/ccb_python]

带参数的decorator和不带参数的其实是有很大不同的。不相信?那自己写一个函数实现的decorator,再同下面这个做下对比:

[ccb_python]
def decorate(message):
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
[/ccb_python]
猜你的反应肯定是:“WTF!怎么会有这么多层函数!”。先别急,把最外面的一层函数去掉,不就是最简单的没有参数的decorator了吗?其实wrap只是在decoration阶段接收message参数,wrapped_f才是真正会调用的函数。

用类实现的就是下面这个样子的了:

[ccb_python]
class Decorator(object):

def __init__(self, message):
self.message = message

def __call__(self, f):

def wrapped_f(*args):
print self.message
return f(*args)

return wrapped_f
[/ccb_python]

Real word decorators

理解decorator的基础之后,再看几个例子。

我们都知道c++的类可以有static方法,这类方法并不属于某一个具体的实例,而是存在于整个类的命名范围之内的。所有的实例都共用这个方法。在python中,我们也可以实现。方法就是是借助[ccib_python]@staticmethod[/ccib_python]这个decorator:

[ccb_python]
class Foo(object):
@staticmethod
def add(x,y):
return x + y

x = Foo.add(3,4)
[/ccb_python]

另外一个常见的decorator就是[ccib_python]@classmethod[/ccib_python]。用classmethod修饰的方法和普通的方法不同,普通的方法第一个参数都是self,而classmethod的第一个参数则是类。例如:

[ccb_python]
class Times(object):
factor = 1
@classmethod
def mul(cls,x):
return cls.factor*x

class TwoTimes(Times):
factor = 2

x = TwoTimes.mul(4)
[/ccb_python]
还有更多的用法,参见这里

参考

  1. Decorators I: Introduction to Python Decorators
  2. Python Decorators II: Decorator Arguments
  3. PythonDecoratorLibrary