commonly accessible instance attributes in function (CAIAF) テクニック
追記(2007/8/2):
namespace function object (NFO) アプローチに改名。
今月25日に使ったテクニックに名前が付いていないので適当に付けた。どこかに付けている人がいそうだが、とりあえず自分の記憶用にメモ。クロージャと組み合わせると便利かも。もし、適切な名前があったり、既にドキュメント化されていたり、使ってみて問題ある場合は教えて欲しい。
テクニックとしては、関数の内部でダミーの関数を作成し、それに属性を関連付けるというもの。以下の2つの機能が実現可能。
- ネストした名前空間を越えて属性がアクセス可能
- 関数の外側に関数内部の属性を公開可能
# 1. def foo(i): def f():pass # ダミーで関数 f を作成 (foo呼び出しごとにインスタンスが作成される) f.n = i # f に変数を関連付ける def cnt(): f.n += 1 # もちろん、値の変更可能 return f.n # ネストした名前空間でアクセス可能 return cnt counter = foo(0) print counter() # 1 print counter() # 2 # 2. def foo(): def f():pass def bar(): return 'bar()' f.x = 1 f.bar = bar # 関数を保持することも可能 return f # f を返値とすることで、外に公開 f = foo() print f.x # 1 print f.bar() # 'bar()'
str.startswith が遅い件
- どう書く?org 実行時間の測定 (http://ja.doukaku.org/22/)
デコレータに対応するようにして、時間計測。
import time def profile(func): def foo(*a, **k): t = time.time() r = func(*a, **k) print '%s: %g sec elapsed' % (func.__name__, time.time() - t) return r return foo if __name__ == '__main__': @profile def find(s1, s2): for i in xrange(100000): str.find(s1, s2) @profile def startswith(s1, s2): for i in xrange(100000): str.startswith(s1, s2) @profile def op_eql(s1, s2): for i in xrange(100000): s1[:5] == s2 find('func_name', 'test_') startswith('func_name', 'test_') op_eql('func_name', 'test_') # find: 0.0939999 sec elapsed # startswith: 0.0780001 sec elapsed # op_eql: 0.016 sec elapsed
実行するたびに若干値は違うが、傾向的にはこんな感じ。文字列の比較する長さによるのかもしれないが、== を使った方法が断然早い。== が成立するときも早い。但し、バージョンが上がったときに順序が逆転する可能性もある。パフォーマンステストは難しいので、とりあえずここまでにしておくつもり。