Monors Note

Pythonとそれ以外いろいろ

7-33. Quiz: Cache Management

目次

MEMO化について

C101においても、プログラムの高速化にメモ化を使用する場面があった。コードは下記のようである。

memo = {}

def fib(n):
    if n in memo:
        return memo[n]
    else:
        memo[n] = result = n * fib(n - 1)
        return result

このようなメモ化はfibの様に再帰処理を行う関数において高速化を行う事が可能であるため、よく用いられる。 再帰がある度にこのコードが書かれるのだ。ここでDRYの法則違反していることが分かる。 DRYの法則を満たすために、デコレーターを作成することにする。

MEMOのデコレータ


メモのデコレータを作成してみる。

@decorater
def memo(f):
    """
  Decorator that caches the return value for each call to f(args).
  Then when called again with same args, we can just look it up.
  """
    cache = {} #->cacheは宣言を外でしていてもよい。
    def _f(*args):
        try:
            return cache[args]
        except KeyError:
            cache[args] = result = f(*args)
            return result
        except TypeError:
            return f(args)
    return _f

Hash TableにListは入れられない??

Hash Tableに数字が入っているかを評価する場合には通る。 しかし、listがHash上にあるかを評価すると、Errorとなる。

a = {}
x = 42
x in d #->False

y = [1,2,3,4]
y in d #-> TypeError: unhashable type:list

これは、listが変更可能なオブジェクトであるためHash TableのKeyとすることができないため。 listでなくTupleならば問題ない。

しかし、([1,2,3,4], 5)はエラーとなる。

a = {}
b = ([1,2,3,4], 5)
a[b] = 'c' # => TypeError: unhashable type:list

なぜなら、TupleにListが入っているように見えるが実際Tupleが保持しているのは Listの参照メモリ。よって、書き換えが可能。

a = {}
b = ([1,2,3,4], 5)
# a[b] = 'c'
b[0][1] = 100
print(b)# => ([1,100,3,4], 5)

ちょうどこんなイメージ f:id:jsakusan:20170512223730p:plain