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

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

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

《著》森こねこ、小粒ちゃん+∞《監修》小泉ひよ子とタマゴ倶楽部
第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.

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

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

次に示すコードの断片

    from time import time

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

    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
    def ex(n): return fib(n)

    for e in range(30):
        r,s = ex(e)
        print("%2d: %6d -> %s"%(e,r,s))
    print("-"*40)
    print("trib:",trib(10))
    print("tetra:",tetra(10))

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

 0:      0 -> 4.05311584473e-06
 1:      1 -> 5.00679016113e-06
 2:      1 -> 8.10623168945e-06
 3:      2 -> 1.00135803223e-05
 4:      3 -> 1.50203704834e-05
 5:      5 -> 2.00271606445e-05
 6:      8 -> 3.00407409668e-05
 7:     13 -> 4.48226928711e-05
 8:     21 -> 6.89029693604e-05
 9:     34 -> 0.000110149383545
10:     55 -> 0.000181913375854
11:     89 -> 0.000290870666504
12:    144 -> 0.000439882278442
13:    233 -> 0.000667095184326
14:    377 -> 0.00115489959717
15:    610 -> 0.00192785263062
16:    987 -> 0.00276112556458
17:   1597 -> 0.00464081764221
18:   2584 -> 0.00439596176147
19:   4181 -> 0.0109350681305
20:   6765 -> 0.0114660263062
21:  10946 -> 0.0185430049896
22:  17711 -> 0.0300748348236
23:  28657 -> 0.04847407341
24:  46368 -> 0.0805361270905
25:  75025 -> 0.132725954056
26: 121393 -> 0.234812021255
27: 196418 -> 0.353581190109
28: 317811 -> 0.574314832687
29: 514229 -> 0.935798168182
                                                                              • -
trib: 81 tetra: 56

が得られます。

■ 解説

デコレーター構文

    @spyOn

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

    ex = spyOn(ex)

と、同じ効果が得られます。つまり、関数 spyOn の実引数に、関数オブジェクト ex を指定したのと同じです。そのため、あたかも関数 spyOn の本体には、次に示すコードの断片

    def spyOn(f):
        ...
            t1 = time(); r = ex(*args); t2 = time()
            return r, t2-t1

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

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

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


関連記事

Last updated♪2010/01/26