Python装饰器是一个很出名的设计模式,它主要的功能就是不改变函数已有功能的情况下对函数起到一个锦上添花的作业,使函数的功能更加丰富,在插入日志,性能测试,缓存机制和权限验证都是比较好的左右。不同的函数可以使用同一个装饰器,所以它和函数本身不存在什么必然的联系。
AOP(面向切面编程): 下面用一个例子来说明:
假设我们定义了一个函数:
def test():
print('in test')
test()
这是一个非常简单的函数,其功能肯定是显而易见了。
现在我们想测试下这个函数的运行时间成本如何 但是我们又不想去改变函数本来的代码 怎么办,在Python中编程会很大程度上用上面向函数编程的思想,这里我们也不能例外。我们重新定义一个函数。哈哈
def test():
print('in test')
def timeit():
start = time.clock()
test()
end = time.clock()
print('foo is used:', end-start)
timeit()
想一想这一样的方式我们的确能达到我们一开始的目的,但是假如我现在有另外一函数也需要测试它的执行时间,怎么办,是修改我们已有的函数还是进行复制再修改 好像都不是太好,那我们就得想一种比较好的方式,让程序能够通用,于是乎,我们就这样办,将函数名作为函数参数传给另一个函数,在另一个函数的内部进行调用,
def test():
print('in test')
def timeit(func):
def wrap():
start = time.clock()
func()
end = time.clock()
print('foo is used:', end-start)
return wrap
test = timeit(test)
test()
这样我们们就实现了代码的可复用性了啊。我们先调用timeit函数并把函数名test作为参数传给它,它会返回内嵌函数的函数名 将这个返回结果赋值给test变量, 此时我们使用test调用的函数就是timeit内部的wrap了啊 这样就实现了我们的目的了。而从一个函数开始处开始计时和退出时需要计时,这被称为一个横切面,这种方式的编程我们称为AOP面向切面编程
这里我们的装饰器还尚未结束,这样的调用方式太过繁琐,也比较难看,Python中提供了语法糖来解决这个问题,那么就是使用@符号对函数进行修饰, 等同上面的语言,这样看起来也更有装饰器的感觉,注意需要将装饰器函数定义在要装饰的函数之前。
def timeit(func):
def wrap():
start = time.clock()
func()
end = time.clock()
print('foo is used:', end-start)
return wrap
@timeit
def test():
print('in test')
test()