44. 使用函数装饰器

某些时候我们想问多个函数统一添加某种功能,比如计时统计、记录日志、缓存运算结果等等。我们不想在每个函数内添加完全相同的代码,如何更好的达成目的呢?

要求:不在每个函数内添加完全相同的代码的前提下实现功能。

解决方案:

定义装饰器函数,用它生成一个在原函数基础上添加了新功能的函数,替代原函数。


  • 对于装饰器decorator:

Python的装饰器decorator本质上是一个高阶函数,它接收一个函数作为参数,然后返回一个新的函数,可以让该函数在不改动源代码的情况下增加其他新功能。

Python通过一个语法糖@符号来使用decorator,这样可以避免编写f = decorate(f)这样形式的代码。所谓的语法糖便是你不使用也可以完成任务,但是使用它可以让你的代码更简洁。

对于装饰器,需要记住的就是

@decoratedef f():
    pass

其中,

@decorate   等价于  f = decorate(f)


  • 方案示例:
1. 斐波那契数列def fib(n):
    if n <= 1:
        return 1
    return fib(n-1) + fib(n-2)print(fib(50))2. 走台阶问题# 台阶有100阶,一个人每次可以走1~3阶。有多少种走法?def climb(n, steps):
    count = 0
    if n == 0:
        count = 1
    elif n > 0:
        for step in steps:
            count += climb(n-step, steps)
    return countprint(climb(100, (1, 2, 3)))

对于求斐波那契数列,递归过程中会反复求值,造成算法效率低;走台阶问题也是如此。

如何提高上面两函数的算法效率,可以通过装饰器函数来缓存运算结果。

def memo(func):
    cache = {}
    def wrap(*args):
        res = cache.get(args)
        if not res:
            res = cache[args] = func(*args)
        return res    return wrap

@memo               #等价于 fib = memo(fib)def fib(n):
    if n <= 1:
        return 1
    return fib(n-1) + fib(n-2)print(fib(50))@memo               #等价于 climb = memo(climb)def climb(n, steps):
    count = 0
    if n == 0:
        count = 1
    elif n > 0:
        for step in steps:
            count += climb(n-step, steps)
    return countprint(climb(100, (1, 2, 3)))

结果:

20365011074
180396380815100901214157639

有了装饰器函数装饰之后,会很快得到运算结果,大大提高了算法效率。


上一篇:使用EXCLE表格,有相同列,取某一列的值


下一篇:100道GO笔试_答案&解析&扩展_选择题21-44