Python

【Python】名前空間とスコープについて

この記事では、Pythonの名前空間とスコープについて解説します。

名前空間とスコープのことを知っておくことで定義した関数やクラスがどこまでの範囲でどのように呼び出せるか知ることができます。

それでは、名前空間とスコープについて見ていきましょう!

名前空間(namespace)とは?

名前空間とは、変数が所属している領域のことを言います。Pythonでは名前空間を名前とオブジェクトが対応付けられた辞書として管理しています。

名前空間の種類

名前空間には、以下のような種類があります。

組み込み名の集合(組み込み関数や組み込み例外名など):

組み込み名の集合の名前空間は、インタプリタが起動する時に作成され、インタプリタが終了するまでずっと保持されます。

モジュール内のグローバルな名前:

モジュールのグローバルな名前空間は、モジュール定義が読み込まれたときに作成され、インタプリタが終了するまで残ります。

関数を呼び出したときのローカルな名前:

関数のローカルな名前空間は、関数が呼び出されたときに作成されます。関数から戻ったときや関数内で例外が送出され、かつ関数内で処理されなかった場合に削除されます。

名前空間の確認

グローバルな名前空間をglobals()関数、ローカルな名前空間をlocals()関数で確認することができます。

def func():
    l = 'ローカル変数'
    print(f'locals: {locals()}')


g = 'グローバル変数'
print(f'globals: {globals()}')

func()

実行結果

globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10444fca0>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': '/Users/yumaru/Desktop/Python/main.py', '__cached__': None, 'func': , 'g': 'グローバル変数'}
locals: {'l': 'ローカル変数'}

スコープ(scope)とは?

スコープとは、直接アクセスできる名前空間の範囲のことを言います。直接アクセスできるということは、obj.xではなくxでアクセスできるということです。

スコープの種類と優先順位

スコープには、以下のような種類があって「1」から順番に検索されます。

1ローカルスコープ

自らの関数のブロック内。

2エンクロージングスコープ

関数がネストされている場合の外側の関数のブロック内。よりローカルに近い方から検索される。

3グローバルスコープ

自らのモジュール内。

4ビルドインスコープ

どこからでも参照できる。組み込み関数や組み込み定数など。

以下は、inner_func関数のブロック内から見たスコープです。

# グローバルスコープ
g = 'グローバル'

def outer_func():
    # エンクロージングスコープ
    e = 'エンクロージング'

    def inner_func():
        # ローカルスコープ
        l = 'ローカル'

変数の再束縛

ローカルスコープ内からグローバルやエンクロージングで宣言された変数は参照することができますが、そのままでは代入することができません。

そんな時は、global文、またはnonlocal文を使います。

# グローバルスコープ
g = 'グローバル'

def outer_func():
    # エンクロージングスコープ
    e = 'エンクロージング'

    def inner_func():

        # グローバル変数を再束縛
        global g

        # グローバルを除く1つ外側のスコープの変数を再束縛
        nonlocal e

        # 再束縛したので代入可能
        g = '書き換えたグローバル'
        e = '書き換えたエンクロージング'

        print(g, e)

    inner_func()


outer_func()
>> 書き換えたグローバル 書き換えたエンクロージング

要するに、global文はグローバル変数を、nonlocal文はグローバル以外の1つ外側のスコープの変数を使うことを明示的に宣言できるってことです。

代入する以外にも同名の変数が存在する場合にも使うことができます。