问题历史:
记忆化是一种优化技术,广泛应用于函数式编程、递归计算和动态编程,当相同的函数以相同的参数重复调用时。它在Python中自从引入了装饰器functools.lru_cache和结果缓存模式后变得流行。
问题:
没有缓存的递归函数,如计算斐波那契数,会运行得非常慢:对于每个参数,计算会重复多次,导致调用数量呈指数增长。
解决方案:
记忆化保存已计算的值(例如,保存在字典中),以便在需要时重复使用:
手动实现示例:
memo = {} def fib(n): if n in memo: return memo[n] if n <= 1: result = n else: result = fib(n-1) + fib(n-2) memo[n] = result return result
从Python 3.2开始,可以直接使用装饰器:
from functools import lru_cache @lru_cache(maxsize=128) def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2)
关键特点:
可以对可变参数的函数进行记忆化(例如,列表)吗?
不可以,lru_cache要求所有参数都是可哈希的(不可变),否则会出现TypeError。
from functools import lru_cache @lru_cache # def f(a): return a[0] # TypeError: unhashable type: 'list'
记忆化的值会自动删除吗?
会的,如果设置了maxsize,则超过限制的值会被删除(最近最少使用)。无限缓存(maxsize=None)可能会导致内存溢出。
如果记忆化函数用新的参数调用自身会发生什么?
记忆化仍然会起作用——对于每一组唯一的参数,结果只计算一次并缓存。
编写自己的缓存而没有限制大小:
cache = {} def foo(x): if x not in cache: cache[x] = long_heavy_computation(x) return cache[x]
过了一段时间,程序使用了数GB的内存。
优点:
缺点:
使用带maxsize的lru_cache:
from functools import lru_cache @lru_cache(maxsize=1000) def foo(x): return long_heavy_computation(x)
优点:
缺点: