2014/02/07

Pythonのスコープ その2

その1につづいて、Pythonのスコープのルールについて見ていきたいと思います。

ふたつめのポイントは「参照の順番は「LEGB」」というものです。

2. 参照の順番は「LEGB」

名前空間が関数やクラスで区切られるのはその1で見たとおりですが、名前を「参照する」という面においては「スコープチェーン」とも言えるような仕組みがPythonには用意されています。

たとえば。
def outer_func():
    Const = 10

    def inner_func():
        # 外側のConstを利用する
        return Const

    return inner_func()

print outer_func()  # => 10
Pythonでは関数内関数ーーいわゆる「関数のネスト」が可能となっていますが、ここで、内側の関数内では、その外側にある関数の変数を「参照」することができます。

具体的には、 inner_func の中で Const という名前が使われていますが、これが呼ばれたときには inner_func の中には Const という名前は存在しません。この場合Pythonインタプリタは inner_func のひとつ外側ーーつまり outer_func の名前空間を探索にいきます。そこには Const という名前が存在するので、その値を利用します。

このようなスコープ拡大、名前探索の順序を表したことばが「LEGB」です。LEGBとは次のことばの頭文字です。

  1. L Local
  2. E Enclosing function local
  3. G Global
  4. B Built-in


意訳すると次のような感じでしょうか。

  1. L ローカル空間
  2. E ひとつ外側にある関数のローカル空間
  3. G グローバル空間(モジュール空間)
  4. B 組み込み空間


意味合いとしては、名前を探索する順番が、最初にローカル空間、続いてひとつ外側にある関数のローカル空間、そこになければグローバル空間(モジュール空間)、それでもダメなら組み込み空間、というところになります。

かんたんな例を見てみます。
sho = 1

def outer():
    chiku = 2

    def inner():
        bai = 3

        print bai    # Lで発見
        print chiku  # Eで発見
        print sho    # Gで発見
        print abs    # Bで発見
innner 関数の中でいろいろな名前を参照しています。baiだけは同じ関数の中(ローカル空間)にその名前があるためそこで解決が済みますが、それ以外の名前はすべて異なる場所で参照を解決しています。

chikuはひとつ外側の関数、shoはモジュールのトップレベル、absは組み込みの名前によって、参照先の値を取得しています。

・・・以上が、Pythonのスコープに関するふたつめのルール「LEGB」です。


ちなみに、 global キーワードを使うと、グローバル空間にある名前を直接指定して参照や代入を行うことが可能となります。
C = 5

def outer():
    C = 10

    def inner():
        global C
        print C  # => 5
        C = 100

    inner()

outer()
print C  # => 100

Python 3では global に加えて、ひとつ外側の関数のローカル空間の名前を指定する nonlocal というキーワードが追加されています。

つづいて、みっつめのポイント「スコープ内で使われる名前はスコープの先頭で作られる」について見ていきます。

Pythonのスコープ その3


参考
scope - Short Description of Python Scoping Rules - Stack Overflow
closures - Python nonlocal statement - Stack Overflow

0 件のコメント: