共计 1574 个字符,预计需要花费 4 分钟才能阅读完成。
感觉这个不像是设计模式,在python的语法糖中包含了一种叫装饰器的东西,正好与设计模式的这个玩意名字也是相同的,其实你读了这篇文章也会发现这两个说的也是同一个东西,没什么区别。
装饰器如果记得不太清楚的话可以看我这篇文章,相信你应该可以看得懂python装饰器探究
套用之前装饰器的一篇文章中介绍装饰器部分时,装饰器主要解决的是一些公共部分的代码复用的问题,当然也可以在不修改原始函数代码的基础上增加新的功能比如log日志。
先看一下原始计算斐波那契算法
def fibonacci(n):
assert(n >= 0), 'n must be >= 0'
return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':
from timeit import Timer
t = Timer('fibonacci(8)', 'from __main__ import fibonacci')
print(t.timeit())
上面这个代码耗时是这个样子的
在每次计算f(4)的时候都要去计算f(3)一直到f(0)这个中间消耗了大量的时间,因此这种原始的算法会带来很大的时间消耗,所以需要优化。
优化的思路就是储存中间计算变量,这样下次需要访问中间变量的时候直接取数据就好了,常见的操作就是使用字典去保存这些中间变量,字典的访问时间复杂度是O(1)高效
下面看一个优化不同数学函数计算的代码,主要在优化数据存储与读取的方式
# coding: utf-8
import functools
def memoize(fn):
known = dict()
@functools.wraps(fn)
def memoizer(*args):
if args not in known:
known[args] = fn(*args)
return known[args]
return memoizer
@memoize
def nsum(n):
'''返回前n个数字的和'''
assert(n >= 0), 'n must be >= 0'
return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):
'''返回斐波那契数列的第n个数'''
assert(n >= 0), 'n must be >= 0'
return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':
from timeit import Timer
measure = [{'exec': 'fibonacci(100)', 'import': 'fibonacci',
'func': fibonacci}, {'exec': 'nsum(200)', 'import': 'nsum',
'func': nsum}]
for m in measure:
t = Timer('{}'.format(m['exec']), 'from __main__ import \
{}'.format(m['import']))
print('name: {}, doc: {}, executing: {}, time: \
{}'.format(m['func'].__name__, m['func'].__doc__,
m['exec'], t.timeit()))
总结
就是使用装饰器模式可以很好的拓展你的软件的新的功能,在不修改原来代码的基础上。从软件的角度来看,Django和Grok都适用装饰器来实现不同的目的,比如控制HTTP压缩和缓存。装饰器模式是实现关注切面的一个很好的解决方案,因为它们通用,而且并不很适合OOP范式。我们在使用案例小节提到了很多的关注切面的种类。实际上,在实现小节演示了一个关注切面的例子:记忆器。我们见到了装饰器如何帮助我们保证代码的整洁,而不用付出性能上的代价。