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 とは次の 4 つの単語の頭文字です。

  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で発見

inner() 関数の中でいろいろな名前を参照しています。 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 件のコメント: