9-1 如何使用函数装饰器
1、[题目1]斐波那契数列,又称黄金分割数列。
指的是这样的一个数列:1,1,2,3,5,8,13,21.。。。。
这个数列从第三项开始,每一项都等于前两项之各。求数列的第n项
def fibonacci(n): if n<=1: return 1 return fibonacci(n-1)+fibonacci(n-2)
这种方法也是C语言常用的递归算法。会进行大量的重复计算。如计算(10)时需要计算(8)和(9),计算(9)时需要计算(7)和(8)
2、[题目2]一个共有10个台阶的楼梯,从下面走到上面,一次只能迈1~3个台阶,
并且不能后退,走完这个楼梯共有多少种方法
这个题目和上个类似,也会产生大量的重复计算。如第一次(1)台阶,剩下有(9)级台阶走法,
def climb(n,steps): count = 0 if n==0: count = 1 elif n>0: for step in steps: count += climb(n - step, steps) return count
下面是具体的优化:
def fibonacci(n,cache=None): #cache(n) #计算开始时先去缓存里找是否计算过n,如存在直接返回,否则计算,并把计算结果放在缓存中。 if cache is None: #创建一个空的字典 cache = {} if n in cache: return cache[n] if n<=1: return 1 cache[n] = fibonacci(n-1,cache)+fibonacci(n-2,cache) return cache[n] if __name__ == '__main__': print fibonacci(50)
输出结果:
结果很快运算出结果20365011074
对于题目二的climb函数,可以使用同样的方法增加缓存功能,假如很多函数都需要这样的功能,这样代码中就会出现大量的重复代码。
我们可以不把实现相同的功能放在函数内部实现,而是提取出来,为每个函数,增加一层包裹函数(wrap),包裹函数实现提取出来的功能,本例为增加缓存功能,并调用原函数。
函数装饰器,就是为了生成包裹函数的。
写装饰器函数
def memo(func): #装饰器也是一个函数,它装饰一个函数(func), # 就是为它所装饰的函数(func)生成一个包裹函数 cache = {} #定义一个缓存cache def wrap(*args):#生成的包裹函数,它的参数与所装饰的函数(func)参数是一致, #但此函数也可能装饰其他函数, # 所以这里参数使用收集的方法(不定长参数) if args not in cache: #因这个函数是要为类似fibonacci()提供功能, #所以这里实现的方法也是为了实现刚才优化的功能 #如果参数不在缓存中,执行原函数并生成缓存 cache[args] = func(*args) #func(*args)参数要拆开还原回去 return cache[args] #返回缓存保存的值 return wrap #返回wrap自身,闭包应该就是这么形成的 #cache 不会因为memo函数结束后就消息,因为这里形成了闭包,在wrap函数里一于永远能访问到cache
def fibonacci(n): if n<=1: return 1 return fibonacci(n-1)+fibonacci(n-2) fibonacci = memo(fibonacci) #memo(fibonacci)函数返回wrap函数,通常把它替换原来函数, #好处是对之前用户是透明的,这样的改动 #对他来说不用做任何修改,这种改动对他来说是稍稍的。
python 为fibonacci = memo(fibonacci) 这种写法提供了更简便的方法。
在定义为fibonacci函数时,直接使用
@memo
def fibonacci(n):
...
@memo def climb(n,steps): count = 0 if n==0: count = 1 elif n>0: for step in steps: count += climb(n - step, steps) return count if __name__ == '__main__': print fibonacci(50) print climb(10,(1,2,3))
输出结果:
20365011074
274
装饰器函数,使原函数在原有的功能基础上增加新的功能的函数,替换原函数,也就是装饰器(decorator)可以给函数动态加上功能
posted on 2018-05-09 16:23 石中玉smulngy 阅读(254) 评论(0) 编辑 收藏 举报