名前解決がパフォーマンスに与える影響

http://blog.miraclelinux.com/asianpen/2008/05/python-code-rea.html#more
でも実験されていますが、もう少し細かいケースで試してみました。

scope_test.py

def with_local(num):
    l = []
    l_value = True
    for i in xrange(num):
        l.append(l_value)

def with_nested(num):
    l = []
    n_value = True
    def nested(num):
        for i in xrange(num):
            l.append(n_value)
    nested(num)

m_value = True
def with_module(num):
    l = []
    for i in xrange(num):
        l.append(m_value)

def with_builtin(num):
    l = []
    for i in xrange(num):
        l.append(True)

if __name__ == "__main__":
    import sys
    from timeit import Timer
    t = sys.argv[1]
    num = sys.argv[2]
    if t == "local":
        def_name = "with_local"
    elif t == "nested":
        def_name = "with_nested"
    elif t == "module":
        def_name = "with_module"
    elif t == "builtin":
        def_name = "with_builtin"
    t = Timer("%s(%s)" % (def_name, num),
        "from __main__ import %s" % def_name)
    print def_name, t.timeit(1)

手元のcoLinux(on ThinkPadX61 Core2 Duo 2GHz)で実行。まずは100万回。

[michisu@colinux] $ python scope_test.py local 1000000                                               [~/python-code-reading]
with_local 0.941817998886
[michisu@colinux] $ python scope_test.py nested 1000000                                              [~/python-code-reading]
with_nested 1.04100513458
[michisu@colinux] $ python scope_test.py module 1000000                                              [~/python-code-reading]
with_module 1.03532505035
[michisu@colinux] $ python scope_test.py builtin 1000000                                             [~/python-code-reading]
with_builtin 1.08331394196

1000万回。

[michisu@colinux] $ python scope_test.py local 10000000                                              [~/python-code-reading]
with_local 9.48914504051
[michisu@colinux] $ python scope_test.py nested 10000000                                             [~/python-code-reading]
with_nested 10.4752728939
[michisu@colinux] $ python scope_test.py module 10000000                                             [~/python-code-reading]
with_module 10.4114220142
[michisu@colinux] $ python scope_test.py builtin 10000000                                            [~/python-code-reading]
with_builtin 10.6834070683

ビルトイン型をそのまま使うとやはり少し遅い。
1000万回回しても1秒程度しか差が出ないので、Setのような汎用コレクションクラスのコードでもない限り、普段は気にしなくても良さそうだけど。(これをつねにやるぐらいならCを使えって話になる)

ある名前がコードブロック内で使われると、その名前を最も近傍から囲うようなスコープ (最内スコープ: nearest enclosing scope) を使って束縛の解決を行います。

http://www.python.jp/doc/2.4/ref/naming.html

ということで、最内スコープによる名前の解決がもっとも高速になり、順次外のスコープが使われるのでルックアップが遅くなると思われます。
上のケースではnestedがmoduleより常に少しだけ遅いのが面白いですが、この理由はよく分かりません。

追記。タイトル変更しました。「スコープの変数解決が」→「名前解決が」
追記2。地の文で回数の桁が間違ってたので直しました。