某些时候我们想问多个函数统一添加某种功能,比如计时统计、记录日志、缓存运算结果等等。我们不想在每个函数内添加完全相同的代码,如何更好的达成目的呢?
要求:不在每个函数内添加完全相同的代码的前提下实现功能。
解决方案:
定义装饰器函数,用它生成一个在原函数基础上添加了新功能的函数,替代原函数。
- 对于装饰器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
有了装饰器函数装饰之后,会很快得到运算结果,大大提高了算法效率。