Python functoolsのlru_cacheの使い方

Python学習【365日チャレンジ!】302日目のマスターU(@Udemy11)です。

年末が近づくとほんといろいろなことをしなくてはいけなくなります。

クリスマスプレゼントの選定に、年賀状作成、大掃除など、結構時間の掛かることがあるので、ホント時間が足りないんですよね。

一つ一つコツコツと片付けていくしかないので、計画を立てて効率よく済ませていこうと思います。

それでは今日も、Python学習を始めましょう。

昨日の復習

昨日は、サーバーの操作で活用できるIntFlagを学習しました。

IntFlagは、UNIX系のサーバーに保存しているファイルのパーミッションの設定で使うことができました。

書き込み、読み込み、実行を整数で定義して、論理和を使った権限の割当に使われたりしています。

サイト運営している人にはおなじみのパーミッションの数字(755とか644など)は、IntFlagを使って条件分岐が設定されているものも多いかもしれませんね。

詳細については昨日の記事をごらんください。

今日は、cacheを使って処理を高速化するlru_cacheを学習します。

cache

cacheは、ネット上のサーバーからデーターを読み込んだ際に一時的に保存したデータのことで、再度そのデータを活用することで、サーバーからデータを読み込むことなくcacheからデータを取り出せるので、処理を早くすることができます。

ブラウザーのキャッシュが最もわかりやすいと思いますが、一度読み込んだサイトは、次に同じサイトを表示するスピードが上がります。

これは、サイトのデータをPCのキャッシュとして保存しているからで、たまに、サイトが更新されているはずなのに、表示されるページが古いままということがあるのはキャッシュを読み込んでいるからです。

Pythonの処理にもcacheを活用して、非常に時間のかかる処理を再利用できるものがあり、それがlru_cacheです。

lru_cache

処理に時間がかかる関数を作成して、実行したあと、lru_cacheを使って再度同じ関数を実行するコードを書いてみます。

import functools

@functools.lru_cache()
def long_func(n):
    r = 0
    for i in range(10000000):
        r += n * i
    return r

for i in range(5):
    print(long_func(i))

print('second run')
for i in range(5):
    print(long_func(i))

1行目でfunctoolsをインポートして、3行目でfunctools.lru_cacheをデコレーターにしています。

実行する関数long_funcは、引数のnに0から99999999をかけてrに足すループの回答を返す関数です。

10行目でforループを使って、関数long_func(i)を0から4まで5回繰り返して出力しています。

出力結果だけでは、実際の動きがわからないので、実行結果の動画をどうぞ

10行目、11行目の実行は結構ゆっくりに対して、14行目と15行目の実行はあっという間に終わってしまいます。

10行目11行目の最後の出力が終わると同時に13行目のsecond run以降が瞬時に出力されるのがわかるかと思います。

maxsize

lru_cacheの引数にはmaxsizeを決めるものがありますが少し注意が必要です。

import functools

@functools.lru_cache(maxsize=3)
def long_func(n):
    r = 0
    for i in range(10000000):
        r += n * i
    return r

for i in range(5):
    print(long_func(i))

print('second run')
for i in reversed(range(5)):
    print(long_func(i))

ハイライトしている行を変更していますが、functools.lru_chacheの引数にmaxsize=3を加えて、14行目のreversedをつけました。

lru_cacheは、ラストインファーストアウトなので、最後に入れたものを最初に出してきます。

つまり最後にキャッシュされたものから出力されるので、14行目のrange()reversedで反対からループを回しているわけです。

maxsize3に指定したので、キャッシュされる値は後ろから3つのみなので、15行目の出力は、反対から3つ出力した時点でキャッシュがなくなり、再度関数を実行するため、処理が遅くなります。

まとめ

Python2のときは、memoizeというデコレーターを使っていたのですが、Python3でmemoizeの機能をfunctoolsで使えるようになりました。

どのような動きをしているのか解説しませんが、下記の記事をごらんになれば、どのような処理がされているか解説されているので、参考にしてみてください。

口うるさく【自分で試すことが大切】とお伝えしていますが、実際は、自分で試さない人が多いんですよね。

お金儲けのノウハウについても、自分で試さない人がいる一方で、試してみて失敗する人、試してお金を儲けられるようになる人がいます。

試してみれば、失敗したとしても経験値はたまりますが、試さなければ経験値はたまりません。

どうせなら、自分でいろいろと試して経験値を上げたほうがいいですよね。

それでは、明日もGood Python!