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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
が得られます。すると、少なくとも 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