Python

【Python】関数の結果をキャッシュして高速化する

この記事では、Pythonで関数をキャッシュし、2度目以降の呼び出しを高速化する方法を解説します。よく使う関数や重い関数なんかはキャッシュしておくことで高速化することができます。それでは、関数のキャッシュ方法を見ていきましょう❗️

関数をキャッシュする方法

関数をキャッシュするには、Python 3.9で追加されたfunctoolsモジュールのcacheデコレータを使うことでめちゃくちゃ簡単に実装できます。

functoolsモジュールは、標準ライブラリです

では、使ってみましょう!

import time

# 関数の実行時間を測るデコレータ
def tictoc(func):
    def _wrapper(*args, **keywargs):
        start_time = time.time()
        result = func(*args, **keywargs)
        print('time: {:.9f} [sec]'.format(time.time() - start_time))
        return result
    return _wrapper


# ここからが本題

import functools


@tictoc
@functools.cache  # デコレータを付与
def func(num):
    # なんらかの重い処理
    for _ in range(1000000):
        num += 1
    return num

# 1度目の呼び出し
func(1)

# 2度目の呼び出し
func(1)

実行結果

time: 0.117470980 [sec]
time: 0.000002146 [sec]

2度目の呼び出しがめちゃくちゃ早くなりました!

引数でキャッシュする

キャッシュには、辞書が使われています。keyに関数に渡された引数、valueに関数の結果を格納しています。

なので、引数はハッシュ可能な値でなければならず、キーワード引数の順序が異なる場合は、異なるキャッシュとして保存されます。

例えば、f(a=1, b=2)f(b=2, a=1)は別。

引数が同じなら同じ値を返す関数に使う

同じ引数を指定しても同じ値を返さない関数をキャッシュしてしまうと、2回目以降に同じ値を返すようになってしまい、その関数の本来の結果を受け取ることができなくなってしまいます。

なので、関数内でrandom()time()などを使っている場合は注意しましょう❗️

自分で実装する

cacheデコレータは、バージョン 3.9からしか使えないので自分で実装する方法を考えてみましょう!

import time

# 実行時間を計測
def tictoc(func):
    def _wrapper(*args, **keywargs):
        start_time = time.time()
        result = func(*args, **keywargs)
        print('time: {:.9f} [sec]'.format(time.time() - start_time))
        return result
    return _wrapper


# キャッシュデコレータ
def cache(func):
    c = {}
    def _wrapper(*args):
        if args not in c:
            c[args] = func(*args)
        return c[args]
    return _wrapper


@tictoc
@cache
def func(num):
    # なんらかの重い処理
    for _ in range(1000000):
        num += 1
    return num


func(1)
func(1)

func(2)
func(2)

実行結果

time: 0.092554092 [sec]
time: 0.000005245 [sec]
time: 0.088145971 [sec]
time: 0.000007153 [sec]

辞書に引数の値のkeyが存在しなければ、辞書[args] = func(*args)を格納します。returnには、辞書[args]で結果を返しています。

まとめ

この記事では、関数をキャッシュして高速化する方法を解説しました。

関数はキャッシュしておくことで、めちゃくちゃ高速化することができます。少しだけ制限はありますが、よく使う関数や重い関数はキャッシュしておきましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

最短3か月でエンジニア転職『DMM WEBCAMP COMMIT』