Python3の時間に関して完全な答えはなかったので、ここで答えを出しました。ここで説明されていることのほとんどは、4.2.2 Python 3ドキュメントの名前の解決で詳しく説明されています。
他の回答で提供されているように、LEGBには、Local、Enclosing、Global、Builtinの4つの基本スコープがあります。これらに加えて、特別なスコープであるクラス本体があります。これは、クラス内で定義されたメソッドの囲みスコープを構成しません。クラス本体内の割り当てにより、そこからの変数がクラス本体にバインドされます。
特に、および以外のブロックステートメントは、変数スコープを作成しません。Python 2ではリスト内包表記は変数スコープを作成しませんが、Python 3ではリスト内包表記内のループ変数は新しいスコープ内に作成されます。def
class
クラス本体の特性を示すため
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
したがって、関数本体とは異なり、変数をクラス本体の同じ名前に再割り当てして、同じ名前のクラス変数を取得できます。この名前をさらに検索すると、代わりにクラス変数に解決されます。
Pythonを初めて使用する多くの人にとって大きな驚きの1つは、for
ループが変数スコープを作成しないことです。Python 2では、リスト内包表記もスコープを作成しません(一方、ジェネレーターとdict内包表記は作成します!)代わりに、関数またはグローバルスコープの値をリークします。
>>> [ i for i in range(5) ]
>>> i
4
内包表記は、Python 2のラムダ式内で変更可能な変数を作成するための狡猾な(または必要であればひどい)方法として使用できます。ラムダ式は、def
ステートメントと同様に変数スコープを作成しますが、ラムダ内ではステートメントを使用できません。Pythonのステートメントである代入は、ラムダでの変数の代入は許可されないことを意味しますが、リスト内包表記は式です...
この動作はPython 3で修正されました-内包表現やジェネレーターが変数をリークすることはありません。
グローバルは本当にモジュールのスコープを意味します。主要なPythonモジュールは__main__
です。インポートされたすべてのモジュールには、sys.modules
変数を介してアクセスできます。へのアクセスを取得するに__main__
はsys.modules['__main__']
、またはを使用できますimport __main__
。そこで属性にアクセスして割り当てることは完全に許容されます。それらは、メインモジュールのグローバルスコープの変数として表示されます。
現在のスコープ(クラススコープを除く)で名前が割り当てられている場合、その名前はそのスコープに属していると見なされます。それ以外の場合は、変数に割り当てられているスコープに属していると見なされます(割り当てられない場合があります)まだ、またはまったくない)、または最後にグローバルスコープ。変数がローカルと見なされているが、まだ設定されていないか、削除されている場合、変数の値を読み取るUnboundLocalError
と、のサブクラスであるが生成されNameError
ます。
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
スコープはグローバル(モジュールスコープ)変数を明示的に変更することを宣言し、グローバルキーワードを使用します。
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
これは、囲んでいるスコープでシャドウされていても可能です。
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
Python 2では、囲んでいるスコープの値を変更する簡単な方法はありません。通常、これは、長さが1のリストなど、変更可能な値を持つことでシミュレートされます。
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
しかしpython 3では、nonlocal
これが救いに来ます:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
nonlocal
ドキュメントはと言います
非ローカルステートメントにリストされている名前は、グローバルステートメントにリストされている名前とは異なり、囲んでいるスコープ内の既存のバインディングを参照する必要があります(新しいバインディングを作成するスコープを明確に決定することはできません)。
つまり、nonlocal
常に名前がバインドされている(つまり、割り当てられている、for
ターゲット変数として、with
句内で、または関数パラメーターとして使用されている)最も内側の外側の非グローバルスコープを指します。
現在のスコープに対してローカルであると見なされない変数、またはそれを囲むスコープは、グローバル変数です。グローバル名はモジュールのグローバル辞書で検索されます。見つからない場合は、組み込みモジュールからグローバルが検索されます。モジュールの名前がpython 2からpython 3に変更されました。Python 2ではそれが__builtin__
あり、Python 3ではそれが呼び出されbuiltins
ます。ビルトインモジュールの属性に割り当てる場合、そのモジュールが同じ名前の独自のグローバル変数でそれらをシャドウしない限り、その後、読み取り可能なグローバル変数として任意のモジュールに表示されます。
組み込みモジュールを読むことも役立ちます。ファイルの一部にpython 3スタイルの印刷関数が必要だが、ファイルの他の部分がまだprint
ステートメントを使用しているとします。Python 2.6-2.7では、次のようにしてPython 3 print
関数を取得できます。
import __builtin__
print3 = __builtin__.__dict__['print']
は、from __future__ import print_function
実際にはprint
Python 2のどこにも関数をインポートしません。代わりprint
に、現在のモジュールのステートメントの解析ルールを無効にし、print
他の変数識別子と同様に処理print
して、関数を組み込み関数で検索できるようにします。