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编辑  收藏  举报

导航