特に再帰的なコードを使用する場合、lru_cache
。キャッシュは、高速で提供する必要があるデータを保存し、コンピューターの再計算を回避するスペースであることを理解しています。
Pythonlru_cache
functoolsから内部的に動作しますか?
特定の答えを探していますが、Pythonの他の部分のような辞書を使用していますか? return
値のみを保存しますか?
Pythonは辞書の上に大きく構築されていることは知っていますが、この質問に対する具体的な答えは見つかりませんでした。うまくいけば、誰かがStackOverflowのすべてのユーザーに対してこの答えを簡略化できることを願っています。
Functoolsのソースはこちらから入手できます。 https://github.com/python/cpython/blob/3.6/Lib/functools.py
Lru_cacheデコレータには、コンテキスト内にcache
辞書があります(すべての装飾された関数には独自のキャッシュ辞書があります)呼び出された関数の戻り値を保存します。辞書キーは、引数に従って_make_key
関数で生成されます。いくつかの大胆なコメントを追加しました:
# one of decorator variants from source:
def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
sentinel = object() # unique object used to signal cache misses
cache = {} # RESULTS SAVES HERE
cache_get = cache.get # bound method to lookup a key or return None
# ...
def wrapper(*args, **kwds):
# Simple caching without ordering or size limit
nonlocal hits, misses
key = make_key(args, kwds, typed) # BUILD A KEY FROM ARGUMENTS
result = cache_get(key, sentinel) # TRYING TO GET PREVIOUS CALLS RESULT
if result is not sentinel: # ALREADY CALLED WITH PASSED ARGUMENTS
hits += 1
return result # RETURN SAVED RESULT
# WITHOUT ACTUALLY CALLING FUNCTION
result = user_function(*args, **kwds) # FUNCTION CALL - if cache[key] empty
cache[key] = result # SAVE RESULT
misses += 1
return result
# ...
return wrapper
ソースコードを確認できます here 。
基本的に、2つのデータ構造、dictionary関数パラメーターをその結果にマッピングする、およびlinked list関数呼び出し履歴を追跡します。
キャッシュは基本的に以下を使用して実装されますが、これは一目瞭然です。
cache = {}
cache_get = cache.get
....
make_key = _make_key # build a key from the function arguments
key = make_key(args, kwds, typed)
result = cache_get(key, sentinel)
リンクされたリストを更新する要点は次のとおりです。
Elif full:
oldroot = root
oldroot[KEY] = key
oldroot[RESULT] = result
# update the linked list to pop out the least recent function call information
root = oldroot[NEXT]
oldkey = root[KEY]
oldresult = root[RESULT]
root[KEY] = root[RESULT] = None
......