Python中的装饰器(decorator) - 函数装饰器

Python中的装饰器(decorator)并不是什么很神秘的火箭科技,但是妙用却很多。对于我等好学之徒,怎么能不深入研究呢?

先放相关代码地址:https://github.com/jiafangtao/web_programming/tree/master/py-decorators

 

关于decorator是什么,这里不做说明了,引用一段话,同学们细读就能理解了。

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())

 

 

你可能感兴趣的:(Python,设计模式)