Python 3の名前空間とスコープ

名前空間

まず、公式サイトの説明をご覧ください。

A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。

名前空間 (namespace) とは、名前からオブジェクトへの対応付け (mapping) です。ほとんどの名前空間は、現状では Python の辞書として実装されています。

名前空間は、プロジェクトでの同じ名前を回避するメソッドを提供します。各名前空間は独立しており、相互に関係がないため、名前空間に同じ名前は許可しませんが、異なる名前空間に影響を与えないため、同じ名前を付けることができます。

コンピュータシステムの例を挙げます。フォルダ(ディレクトリ)には複数のフォルダを含めることができます。各フォルダに同じファイル名を付けることはできませんが、異なるフォルダ内のファイルに同じ名前を付けることはできます。

名前空間には次の3種類があります。

  • 組み込み名とは、関数名abs、char、例外名(BaseException、Exception)などのPython言語に組み込む名前です。
  • グローバル名(モジュールで定義されている名前)とは、関数、クラス、その他のインポートされたモジュール、モジュールレベルの変数、定数など、モジュールの変数を記録します。
  • ローカル名(関数で定義された名前)とは、関数パラメータやローカルで定義された変数など、関数の変数を記録します。 (クラスで定義された名前もローカル名である)

名前空間の検索順序:

変数ceodataを使用する場合、Pythonの検索順序は次のとおりです。ローカル名前空間->グローバル名前空間->組み込み名前空間。

変数ceodataが見つからない場合は、検索を中止し、NameError例外を発生させます。

NameError: name ‘ceodata’ is not defined。

名前空間のライフサイクル:

名前空間のライフサイクルは、オブジェクトのスコープによって異なります。オブジェクトの実行が完了すると、名前空間のライフサイクルは終了します。
そのため、外層名前空間から内部名前空間のオブジェクトにアクセスできません。

実例

# var1 はグローバル名です
var1 = 5
def some_func(): 
  
    # var2 はローカル名です
    var2 = 6
    def some_inner_func(): 
  
        # var3 はネストされたローカル名です
        var3 = 7

次の図が示すように、同じオブジェクト名が複数の名前空間に存在できます。

スコープ

A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.

スコープは、Pythonプログラムが名前空間に直接アクセスできる本文範囲です。

Pythonプログラムでは、変数に直接アクセスすると、変数が見つかるまで内部から外層まですべてのスコープにアクセスします。見つけない場合、定義されていないエラーが報告されます。

Pythonでは、プログラムの変数にすべての場所でアクセスできるわけではなく、アクセス許可は変数が割り当てられている場所によって異なります。

変数のスコープによって、プログラムのどの部分がどの特定の変数名にアクセスできるかが決まります。 Pythonには4つのスコープがあります。

4つのスコープは次の通りです。

  • L(Local):最内側、ローカル変数を含みます。例えば、関数/メソッドの内部です。
  • E(Enclosing):非ローカル(non-local)と非グローバル(non-global)変数が含まれます。例えば、2つのネスト関数、関数(またはクラス)Aには関数Bが含まれ、Bの名前にとってはAのスコープはnonlocalです。
  • G(Global):現在のスクリプトの最外層です。例えば、現在のモジュールのグローバル変数などです。
  • B(Built-in):組み込み変数/キーワードなどが含まれます。最後に検索します。
  • ルールの順序: L –> E –> G –>gt; B。

ローカルで見つからない場合はローカルで見つかり、見つからない場合はグローバルで見つかり、最後は組み込みで見つかります。

g_count = 0  # グローバルスコープ
def outer():
    o_count = 1  # クロージャ関数の外層にある関数の内部
    def inner():
        i_count = 2  # ローカルスコープ

組み込みスコープは、builtinと呼ばれる標準モジュールによって実装されますが、変数名自体は組み込みスコープに入れられないため、このファイルを使用するには、このファイルをインポートする必要があります。Python 3.0では、下記のコードを使用して、事前定義されている変数を確認できます。

>>> import builtins
>>> dir(builtins)

Pythonでは、モジュール(module)、クラス(class)、関数(def、lambda)のみが新しいスコープを導入し、他のコードブロック( if/elif/else/、try/except、for/whileなど)は新しいスコープに導入しません。つまり、これらのステートメントで定義された変数に外層からアクセスできることを意味します。次の通りです。

>>> if True:
...  msg = 'I am from Florian Studio'
... 
>>> msg
'I am from Florian Studio'
>>> 

この例では、msg変数はifステートメントブロックで定義されていますが、外層からアクセスできます。

msgが関数で定義されている場合、それはローカル変数であり、外層からアクセスできません。

>>> def test():
...     msg_inner = 'I am from Florian Studio'
... 
>>> msg_inner
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
>>> 

エラーメッセージから判断すると、msg_innerは定義されていません。ローカル変数であるため、関数の内部しか使用できません。

グローバル変数とローカル変数

関数内部で定義された変数にはローカルスコープがあり、関数外層で定義された変数にはグローバルスコープがあります。

ローカル変数は、それらが宣言されている関数内でのみアクセスできますが、グローバル変数は、プログラム全体のスコープ内でアクセスできます。関数を呼び出すと、関数で宣言されているすべての変数名がスコープに追加されます。次には例を挙げます。

実例(Python 3.0+)

#!/usr/bin/python3
 
total = 0 # これはグローバル変数である
# 関数説明の記入は可能だ
def sum( arg1, arg2 ):
    #2つのパラメータの合計を返す."
    total = arg1 + arg2 # totalこれがローカル変数である.
    print ("関数内部にはローカル変数 : ", total)
    return total

#sum関数を呼び出す
sum( 10, 20 )
print ("関数外層にはグローバル変数 : ", total)

上記の例の結果:

関数内部にはローカル変数:30
関数外層にはグローバル変数:0

キーワードglobalとnonlocal

内部のスコープが外層のスコープの変数を変更する場合、キーワードglobalとnonlocalを使用する必要があります。

次の例では、グローバル変数numを修正します。

実例(Python 3.0+)

#!/usr/bin/python3
 
num = 1
def fun1():
    global num  # キーワードglobalによって宣言する必要がある
    print(num) 
    num = 123
    print(num)
fun1()
print(num)

上記の例の結果:

1
123
123

ネストされたスコープ(enclosingスコープ、外層のnonglobalスコープ)の変数を変更する場合には、nonlocalキーワードが必要です。次には例を挙げます。

実例(Python 3.0+)

#!/usr/bin/python3
 
def outer():
    num = 10
    def inner():
        nonlocal num   #キーワードnonlocalを宣言する
        num = 100
        print(num)
    inner()
    print(num)
outer()

上記の例の結果:

100
100

次には特別な例を挙げます。仮に、下記のコードが実行されます。

実例(Python 3.0+)

#!/usr/bin/python3
 
a = 10
def test():
    a = a + 1
    print(a)
test()

上記のプログラムが実行されると、エラーメッセージは次のようになります。

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    test()
  File "test.py", line 5, in test
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

エラーメッセージはローカルスコープ参照エラーです。test関数のaはローカルで、定義されていないため、変更できません。

aをグローバル変数に変更します。

実例

#!/usr/bin/python3
 
a = 10
def test():
    global a
    a = a + 1
    print(a)
test()

結果は次のとおりです。

11 

関数のパラメータによって渡すこともできます。

実例(Python 3.0+)

#!/usr/bin/python3
 
a = 10
def test(a):
    a = a + 1
    print(a)
test(a)

結果は次のとおりです。

11 
Share

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です