我剛開始使用Python, 卻不知道什麼是記憶以及如何使用它。 另外,我能夠舉一個簡化的例子嗎? html
備註基本上是保存使用遞歸算法完成的過去操做的結果,以減小在之後須要相同計算時遍歷遞歸樹的需求。 python
參見http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/ 算法
Python中的斐波那契記憶示例: 緩存
fibcache = {} def fib(num): if num in fibcache: return fibcache[num] else: fibcache[num] = num if num < 2 else fib(num-1) + fib(num-2) return fibcache[num]
cache = {} def fib(n): if n <= 1: return n else: if n not in cache: cache[n] = fib(n-1) + fib(n-2) return cache[n]
Python 3.2的新功能是functools.lru_cache
。 默認狀況下,它僅緩存最近使用的128個調用,可是您能夠將maxsize
設置爲None
以指示緩存永不過時: ide
import functools @functools.lru_cache(maxsize=None) def fib(num): if num < 2: return num else: return fib(num-1) + fib(num-2)
此功能自己很是慢,嘗試使用fib(36)
,您將不得不等待大約十秒鐘。 wordpress
添加lru_cache
註釋可確保若是最近已爲特定值調用了該函數,則不會從新計算該值,而是使用已緩存的先前結果。 在這種狀況下,它能夠極大地提升速度,而代碼不會因緩存的細節而混亂。 函數
這是一個能夠解決列表或字典類型參數而無需抱怨的解決方案: spa
def memoize(fn): """returns a memoized version of any function that can be called with the same list of arguments. Usage: foo = memoize(foo)""" def handle_item(x): if isinstance(x, dict): return make_tuple(sorted(x.items())) elif hasattr(x, '__iter__'): return make_tuple(x) else: return x def make_tuple(L): return tuple(handle_item(x) for x in L) def foo(*args, **kwargs): items_cache = make_tuple(sorted(kwargs.items())) args_cache = make_tuple(args) if (args_cache, items_cache) not in foo.past_calls: foo.past_calls[(args_cache, items_cache)] = fn(*args,**kwargs) return foo.past_calls[(args_cache, items_cache)] foo.past_calls = {} foo.__name__ = 'memoized_' + fn.__name__ return foo
請注意,經過在handle_item中做爲特殊狀況實現本身的哈希函數,能夠天然地將此方法擴展到任何對象。 例如,要使此方法適用於將集合做爲輸入參數的函數,能夠將其添加到handle_item中: code
if is_instance(x, set): return make_tuple(sorted(list(x)))
記憶有效地指基於方法輸入記憶方法調用的結果(「記憶」→「備忘錄」→要記憶),而後返回記憶的結果,而不是再次計算結果。 您能夠將其視爲方法結果的緩存。 有關更多詳細信息,請參見第387頁的Cormen等人的算法簡介 (3e)中的定義。 orm
一個簡單的示例,使用Python中的記憶來計算階乘是這樣的:
factorial_memo = {} def factorial(k): if k < 2: return 1 if k not in factorial_memo: factorial_memo[k] = k * factorial(k-1) return factorial_memo[k]
您可能會變得更加複雜,並將備註過程封裝到一個類中:
class Memoize: def __init__(self, f): self.f = f self.memo = {} def __call__(self, *args): if not args in self.memo: self.memo[args] = self.f(*args) #Warning: You may wish to do a deepcopy here if returning objects return self.memo[args]
而後:
def factorial(k): if k < 2: return 1 return k * factorial(k - 1) factorial = Memoize(factorial)
Python 2.4中添加了一個稱爲「 裝飾器 」的功能,使您如今只需編寫如下代碼便可完成相同的操做:
@Memoize def factorial(k): if k < 2: return 1 return k * factorial(k - 1)
Python Decorator庫有一個相似的裝飾器,稱爲memoized
,它比此處顯示的Memoize
類更健壯。