Python中的装饰器(decorator)并不是什么很神秘的火箭科技,但是妙用却很多。对于我等好学之徒,怎么能不深入研究呢?
先放相关代码地址:https://github.com/jiafangtao/web_programming/tree/master/py-decorators
关于decorator是什么,这里不做说明了,引用一段话,同学们细读就能理解了。
A decorator in Python is any callable Python object that is used to modify a function or a class. A reference to a function "func" or a class "C" is passed to a decorator and the decorator returns a modified function or class.
关于“装饰器”设计模式,请自行参考GoF的《设计模式》一书。
下面跟随Bruce老师先看看代码,了解装饰器能够做什么。我们从最简单的函数装饰器入手。
#
# Some function decorators
#
def increase(func):
"""
increase is a function decorator which adds 1 to the result of the callee
"""
def decorated_func(*args, **kwargs):
result = func(*args, **kwargs)
return result + 1
return decorated_func
@increase
def get_dimensions():
return 3
@increase
def plus(x, y):
return x + y
##########################################################
def ignore(func):
"""A decorator makes the callee being ignored"""
def no_op(*args, **kwargs):
return None
return no_op
@ignore
def say_hello(greetings):
print "hello, {}".format(greetings)
@ignore
def plus3(x, y, z):
return x + y + z
#########################################################
# utility to log function durations
#########################################################
from datetime import datetime
def duration(func):
def func_wrapper(*args, **kwargs):
print "before calling function " + func.__name__
startTime = datetime.now()
ret = func(*args, **kwargs)
endTime = datetime.now()
d = endTime - startTime
print "after calling function " + func.__name__
print "duration is {} seconds".format(d.seconds + d.microseconds / 1000000.0)
return func_wrapper
import time
import random
@duration
def a_time_consuming_func():
timeout = 5 * random.random()
time.sleep(timeout)
#
# decorations with parameters
#
def repeat(n):
if (n <= 1):
n = 1
def repeat_decorator(func):
def func_wrapper(*args, **kwargs):
for i in range(n):
func(*args, **kwargs)
return func_wrapper
return repeat_decorator
@repeat(3)
def draw_line():
print "--------------------------------------"
if __name__ == '__main__':
print get_dimensions()
print plus(500, 500)
say_hello('bruce.jia')
print plus3(1, 2, 3)
a_time_consuming_func()
draw_line()
最容易实现的是无参数的装饰器,例如@increase和@ignore。使用过JUnit或NUnit的同学们看到@ignore的时候是不是觉得很熟悉呢!它会忽略掉它所装饰的函数。
@duration是个有用的小工具(utility),用来记录一个函数的运行时间。类似与@duration我们也可以用decorator来做安全检查,异常处理,支持实务等等。看到这里,熟悉JAVA的同学是不是想起熟悉的AOP,没错,decorator跟AOP有异曲同工之处。
接下来的@repeat复杂一点,它是一个带参数的decorator。例如重复执行函数三次,可以写@repeat(3)。注意它的实现方式,它其实是一个普通函数,返回一个decorator。而之前的无参数的decorator,返回一个普通函数。
下面的代码跟上边的不同之处,是使用类来实现decorator。
class Auth:
def __init__(self, func):
self._func = func
def __call__(self):
print "authenticate the user before calling the function {}".format(self._func.__name__)
print "......"
return self._func()
@Auth
def get_my_balance():
return 99999999999
if __name__ == '__main__':
print "I'm rich that I have {} dollars".format(get_my_balance())