Python.use(better) 《余録》デコレーター #6:適用事例

記事一覧 Python.use(better)《Python3.1》

デコレーター #6:適用事例

《著》森こねこ、小粒ちゃん+∞《監修》小泉ひよ子とタマゴ倶楽部
第0版♪2001/03/02 ● 第1版♪2003/05/25 ● 第2版♪2004/06/01 ● 第3版♪2009/02/28

例題によって「基本構文」の理解を深めます。
※ Python2.4 で作成した例題を、Python3.1 で再構成しました。

■ JPython 演習課題 #2: フィボナッチ/トリボナッチ/テトラナッチ

《学習のポイント》実行時間を測定する例題によって、デコレーター構文の理解を深めます。

  • Smalltalk 3分クッキング《問2》フィボナッチ/トリボナッチ/テトラナッチ, 1988.

事例:実行時間を測定する

■ 事例6:フィボナッチ数、トリボナッチ数、テトラナッチ数

次に示すコードの断片

    from time import time

    def spyOn(t):
        def h(f):
            def g(*args):
                t1 = time(); r = f(*args); t2 = time()
                dt = t2-t1
                return r, t < dt, dt
            return g
        return h

    def fact(n):
        if n==0: return 1
        return n*fact(n-1)

    def fib(n):
        if n<2: return (0,1)[n]
        return fib(n-2)+fib(n-1)

    def trib(n):
        if n<3: return (0,0,1)[n]
        return trib(n-3)+trib(n-2)+trib(n-1)

    def tetra(n):
        if n<4: return (0,0,0,1)[n]
        return tetra(n-4)+tetra(n-3)+tetra(n-2)+tetra(n-1)

    @spyOn(1.0)
    def ex(n): return fib(n)

    n = 0
    while True:
        r,s,t = ex(n); n += 1
        if s:
            print("%2d: %6d -> %s"%(n,r,t))
            break
    print("-"*40)
    print("trib:",trib(10))
    print("tetra:",tetra(10))

を実行すると、次のような出力結果

30: 832040 -> 1.38019895554
                                                                              • -
trib: 81 tetra: 56

が得られます。すると、少なくとも 1.0 秒の実行時間が掛かるのは、fib(30) からだと分かります。

■ 解説

デコレーター構文

    @spyOn(1.0)

を評価すると、関数 spyOn を呼び出します。デコレーター @spyOn(1.0) で関数 ex を修飾すると、次に示す

    ex = spyOn(1.0)(ex)

と、同じ効果が得られます。つまり、

  • 関数呼び出し spyOn(1.0) のリターン値として、関数(呼び出し可能オブジェクト)が得られ、
  • その関数の実引数に、関数オブジェクト ex を指定した

のと同じです。そのため、あたかも関数 spyOn の本体には、次に示すコードの断片

    def spyOn(t):
        ...
                t1 = time(); r = ex(1.0); t2 = time()
                return r, t < t2-t1, t2-t1

が記述してあるかのような動作を示します。すると、時刻 t1 から t2 までの経過時間を計算して、関数 ex の実行時間を測定するとともに、指定した時間 t(上限)を経過したかを判定できます。

《Note》「フィボナッチ数」を題材にした事例 fib は、再帰呼び出しによって「いかに実行速度が劣化するか」を測定する「劣勢ベンチマーク」として重宝します。良い子のみなさんは「危険ではありませんが」真似をしないように注意してくださいね。(ε_ε) □

》こちらに移動中です《
TOP


関連記事

Last updated♪2010/02/07