Python : 名前空間とスコープ、クロージャ
参考書籍 : Python実践入門
・名前空間の作成されるタイミング
組み込みオブジェクトの名前空間 - Python起動時
モジュールのグローバルな名前空間 - モジュール読み込み時
関数のローカルな名前空間 - 関数呼び出し時
クラスの名前空間 - クラス定義時
・スコープ
scratch.py
# scratchモジュールのグローバルスコープ def f(): # 関数f()のローカススコープ # 関数g()のエンクロージングスコープでもある pass def g(): # 関数g()のローカルスコープ pass def h(): # 関数hのローカルスコープ pass
1, ローカルスコープ
関数(メソッド)の定義時や内包表記で作成されるスコープ
その関数内でしか参照できない
2, グローバルスコープ
モジュールのトップレベルのスコープ
同じモジュール内から参照できる。
別のモジュールで同じ名前の変数が定義されても、別のモジュールからはインポートしない限り参照できない
モジュールの中で、グローバル変数と同じ名前のローカル変数を作成し、ローカルスコープからその名前の変数にアクセスするとき、ローカル変数が優先される。
関数内(ローカル関数内)から、グローバル変数の値を買い替えたい場合は、globan文を使う。
3, エンクロージングスコープ
入れ子になった関数における、1つ外側の関数のローカルスコープ
ローカルスコープとグローバルスコープの中間になる。
入れ子になった関数からエンクロージングスコープの変数の値を書き換えるには、nonlocal文を使う。
4, ビルトインスコープ
組み込み関数やTrue, False, Noneなどの、組み込みオブジェクトの名前空間。
一番最後に検索される。
def counter(): count = 0 def _increment(): nonlocal count count += 1 return count return _increment counter1 = counter() print(counter1) # <function counter.<locals>._increment at 0x02FC7100> print(counter1()) # 1 print(counter1()) # 2
クロージャである関数オブジェクト_increment()がエンクロージングスコープのcountを保持するため、_increment()が実行されるたびにcountがインクリメントされる。
別のカウンタを用意しても、違う変数への参照になりお互いに影響しない
counter2 = counter() print(counter2()) # 1 print(counter2()) # 2