2013.06.17
Pythonで「メモ化(Memoization)」の効いたプロパティがかんたんに作れる「memoize(メモワイズ)」
Python Package Index - memoize
https://pypi.python.org/pypi/memoize/

GitHub - sionide21 / memoize
https://github.com/sionide21/memoize

「memoize(メモワイズ)」は、Pythonで「メモ化(memoize / memoization)」の効いたプロパティがかんたんに作れるライブラリ。作者はBen Olive

ウィキペディア - メモ化
http://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E5%8C%96

<メモ化(英: Memoization)とは、プログラムの高速化のための最適化技法の一種であり、サブルーチン呼び出しの結果を後で再利用するために保持し、そのサブルーチン(関数)の呼び出し毎の再計算を防ぐ手法である>。

「メモ化(Memoization)」とは、かんたんに言うと、計算結果を保持しておいて、同じ計算を2度やらないようにする手法である。

メモ化は有名な手法なので、各言語にライブラリがたくさんあるようで、Pythonにも同種のものがすでにけっこうある。この「memoize(メモワイズ)」も、特に目新しいものではないが、メモ化だけに特化しており、コードもきわめて小さく、わかりやすいので、紹介してみたい。

memoizeは、次のようにして使う(以下はページにのっているコード例)。

from memoize import mproperty

class Foo(object):
    @mproperty
    def bar(self):
        return 2 * 2 * 2

メモ化したいメソッド(ここでは「bar」)に、このように「mproperty」というデコレータ(「@」からはじまる)をつけるだけだ。Python組み込みの(読み取り)プロパティ作成デコレータは「property」なので、その先頭に「m」をつけたものにしたのだろう。

「mproperty」デコレータをつけた(引数なしの)メソッドは、プロパティとしてアクセスできる。これはPython組み込みの「property」デコレータと同じである。異なるのは、「mproperty」はメモ化されたプロパティをつくってくれるので、メソッド内部の計算は、2回目からは呼ばれない、というところだ。

Python組み込みの「property」では、プロパティにアクセスされるたびに、そのメソッド内部の計算がおこなわれる。「mproperty」は、1回目に呼ばれたとき、その計算結果をオブジェクト上に保存しておき、2回目からはそのキャッシュを使う。これが「メモ化」の手法である。オブジェクトが生存している限り、そのキャッシュは有効なので、同じ計算が2回おこなわれることはない。

memoizeライブラリは、「memoize.py」というファイル1個だけでできている。その中身は、以下のようなものだ。

from functools import wraps

def mproperty(fn):
    attribute = "_memo_%s" % fn.__name__

    @property
    @wraps(fn)
    def _property(self):
        if not hasattr(self, attribute):
            setattr(self, attribute, fn(self))
        return getattr(self, attribute)

    return _property

たったこれだけである。

関数「mproperty」がデコレータで、「fn」がデコレータをつけるメソッド、「self」がインスタンスである。

ここでやっていることは、かんたんにいうと、元の「fn」メソッドをラップする「_property」という関数を作って、それを「fn」と置き換える、というものだ。「_property」の中では、インスタンス(self)の上に、fnの計算結果をキャッシュしておき、キャッシュがあるときはそれを使う、というふうにしている。

これくらいであれば、Pythonを多少勉強すれば、誰でも書ける。じっさい、ソフトウェア開発の現場では「メモ化」はしょっちゅう使われるので、このくらいのものは、いちいちライブラリを探したりせず、自分でサッサと書いてしまうのが普通だろう。

この「memoize」ライブラリがいいのは、そこをあえてライブラリにして、わざわざ公開しているところだろう。もちろん実用的にも使えるが、このたった数行の小さいコードが、Python初学者にはとても勉強になる。

「メモ化」はほんとうに、しょっちゅう使うので、Pythonの標準ライブラリに入っていてもおかしくないと思う。「mproperty」というのは、デコレータの表記としてもわかりやすいので、このまま標準ライブラリに入ってほしいくらいだ。


関連エントリ:
Pythonを始めるなら、1ファイルの軽量Webフレームワーク「Bottle」がおすすめ
http://mojix.org/2013/01/04/python-bottle