Pythonのスコープ規則は正確に何ですか?
私がいくつかのコードを持っているならば:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
x
はどこにありますか?いくつかの可能な選択肢は以下のリストを含みます:
関数spam
が他の場所に渡されたときの実行中のコンテキストもあります。そして、おそらく ラムダ関数 は少し違った方法で渡しますか?
単純な参照またはアルゴリズムがどこかにあるはずです。中級のPythonプログラマーにとっては混乱する世界です。
実際のところ、Pythonスコープの解決のための簡潔な規則は、 Pythonの学習から、第3回です。編 (これらの規則は、属性ではなく変数名に固有のものです。ピリオドなしで参照した場合、これらの規則が適用されます。)
LEGBルール.
L、Local - 関数内で何らかの方法で割り当てられた名前(def
またはlambda
))で、その関数内でグローバル宣言されていないもの。
E、Enclosing-function locals - 内側から外側に向かって、すべての静的包含関数(def
またはlambda
)のローカルスコープ内の名前です。
G、Global(module) - モジュールファイルの最上位レベルで割り当てられた名前、またはファイル内のglobal
内のdef
ステートメントの実行によって割り当てられた名前。
B、組み込み(Python) - 組み込みの名前モジュールで事前に割り当てられた名前:open
、range
、SyntaxError
、...
だから、の場合
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Forループには独自のネームスペースはありません。 LEGBの順番では、スコープは次のようになります。
L:ローカル、def spam
内(code3
、code 4
、code5
内).
E:囲まれた関数、それを囲む関数(例全体が別のdef
にある場合)
G:グローバル。モジュール内でグローバルに宣言されたx
がありましたか(code1
)。
B:Pythonに組み込まれているすべてのx
。
x
がcode2
に含まれることは決してありません(期待される場合であっても、 Anttiの答え または を参照してください )。
基本的に、新しいスコープを導入するPythonで唯一のものは関数定義です。本体で直接定義されたものはすべてクラスの名前空間に配置されるという点で、クラスはちょっと特別なケースですが、それらが含むメソッド(またはネストされたクラス)内から直接アクセスすることはできません。
あなたの例ではxが検索される3つのスコープしかありません:
スパムの範囲 - code3とcode5で定義されたすべてのもの(およびcode4、ループ変数)を含む
グローバルスコープ - code1で定義されたすべてのものとFoo(およびその後の変更)を含みます。
組み込み名前空間。ちょっと特別なケース - これは様々なPython組み込み関数とlen()やstr()のような型を含みます。一般的にこれはいかなるユーザコードによっても変更されるべきではないので、それは標準的な関数と他には何も含まないことを期待します。
より多くのスコープは、ネストした関数(またはラムダ)を図に導入したときにのみ表示されます。これらはあなたが期待していたのとほとんど同じように振る舞うでしょう。ネストした関数は、ローカルスコープ内のすべてのもの、およびそれを囲む関数のスコープ内のすべてのものにアクセスできます。例えば。
def foo():
x=4
def bar():
print x # Accesses x from foo's scope
bar() # Prints 4
x=5
bar() # Prints 5
制限事項:
ローカル関数の変数以外のスコープ内の変数にアクセスすることはできますが、それ以上の構文がないと新しいパラメータにリバウンドすることはできません。代わりに、代入は、親スコープ内の変数に影響を与えるのではなく、新しいローカル変数を作成します。例えば:
global_var1 = []
global_var2 = 1
def func():
# This is OK: It's just accessing, not rebinding
global_var1.append(4)
# This won't affect global_var2. Instead it creates a new variable
global_var2 = 2
local1 = 4
def embedded_func():
# Again, this doen't affect func's local1 variable. It creates a
# new local variable also called local1 instead.
local1 = 5
print local1
embedded_func() # Prints 5
print local1 # Prints 4
関数スコープ内からグローバル変数のバインディングを実際に変更するには、globalキーワードを使用して変数がグローバルであることを指定する必要があります。例えば:
global_var = 4
def change_global():
global global_var
global_var = global_var + 1
現在のところ、関数スコープ内の変数に対して同じことをする方法はありませんが、Python 3ではglobalと同じように機能する新しいキーワード "nonlocal
"が導入されていますが、入れ子にされた関数スコープのために。
Python3の時間に関して完全な答えはありませんでしたので、ここで答えを作りました。
他の回答で提供されているように、Local、Enclosing、Global、Builtinの4つの基本的なスコープ、LEGBがあります。これらに加えて、特別なスコープ、クラス本体があります。これはクラス内で定義されたメソッドのスコープを構成しません。クラス本体内の代入は、それ以降の変数をクラス本体内にバインドします。
特に、def
とclass
以外のnoブロックステートメントは、変数スコープを作成します。 Python 2ではリスト内包表記は変数スコープを作成しませんが、Python 3ではリスト内包表記内のループ変数は新しいスコープ内に作成されます。
クラス本体の特殊性を実証する
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では、リスト内包表記もスコープを作成しません(ジェネレータと辞書内包表記は作成しますが)。代わりに、関数内またはグローバルスコープ内の値をリークします。
>>> [ 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()
スコープは、globalキーワードを使用して、グローバル(モジュールスコープ)変数を明示的に変更することを宣言できます。
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.
現在のスコープに対してローカルであるとは見なされていない変数、またはそれを包含するスコープは、グローバル変数です。グローバル名はモジュールのグローバル辞書で調べられます。見つからなかった場合、グローバルはビルトインモジュールから検索されます。モジュールの名前が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
は実際にはPython 2のどこにもprint
関数をインポートしません - 代わりにそれは他の変数識別子のようにprint
を扱い、現在のモジュールのprint
文の解析規則を無効にします。したがって、print
関数を組み込み関数で検索することができます。
Python 2.xのスコープ規則は他の回答ですでに概説されています。私が追加する唯一のことは、Python 3.0には、( 'nonlocal'キーワードで示される)非ローカルスコープの概念もあるということです。これは外部スコープに直接アクセスすることを可能にし、(可変オブジェクトを含む醜いハックなしで)字句クロージャを含むいくつかのきちんとしたトリックをする能力を切り開きます。
編集:これはこれに関する詳細な情報を含む PEP です。
もう少し完全なスコープの例:
from __future__ import print_function # for python 2 support
x = 100
print("1. Global x:", x)
class Test(object):
y = x
print("2. Enclosed y:", y)
x = x + 1
print("3. Enclosed x:", x)
def method(self):
print("4. Enclosed self.x", self.x)
print("5. Global x", x)
try:
print(y)
except NameError as e:
print("6.", e)
def method_local_ref(self):
try:
print(x)
except UnboundLocalError as e:
print("7.", e)
x = 200 # causing 7 because has same name
print("8. Local x", x)
inst = Test()
inst.method()
inst.method_local_ref()
出力:
1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200
Pythonは、3つの名前空間を使って変数を解決します。
実行中はいつでも、名前空間に直接アクセスできる少なくとも3つのネストされたスコープがあります。最初に検索される最も内側のスコープには、ローカル名が含まれます。包含関数の名前空間。最も近い包含スコープから検索されます。次に検索される中央のスコープには、現在のモジュールのグローバル名が含まれています。そして最も外側のスコープ(最後に検索される)は組み込みの名前を含む名前空間です。
globals
とlocals
の2つの関数があり、これらの名前空間のうちの2つの内容を表示します。
名前空間は、パッケージ、モジュール、クラス、オブジェクト構成、および機能によって作成されます。他の種類の名前空間はありません。
この場合、x
という名前の関数への呼び出しは、ローカル名前空間またはグローバル名前空間で解決する必要があります。
この場合、localはメソッド関数Foo.spam
の本体です。
グローバルは - まあ - グローバルです。
規則は、メソッド関数(およびネストした関数定義)によって作成されたネストされたローカルスペースを検索してから、グローバルを検索することです。それでおしまい。
他にスコープはありません。 for
ステートメント(およびif
やtry
などの他の複合ステートメント)は、新しい入れ子スコープを作成しません。定義のみ(パッケージ、モジュール、関数、クラス、およびオブジェクトインスタンス)
クラス定義内では、名前はクラス名前空間の一部です。たとえばcode2
はクラス名で修飾する必要があります。通常はFoo.code2
です。しかし、self.code2
はPythonオブジェクトがフォールバックとして包含クラスを見ているのでうまくいきます。
オブジェクト(クラスのインスタンス)はインスタンス変数を持ちます。これらの名前はオブジェクトの名前空間にあります。それらはオブジェクトによって修飾されなければなりません。 (variable.instance
)
クラスメソッド内からは、ローカルとグローバルがあります。インスタンスを名前空間として選ぶためにself.variable
を言います。 self
はすべてのクラスメンバ関数への引数であり、ローカル名前空間の一部になっていることに気付くでしょう。
Pythonスコープルール 、 Pythonスコープ 、 変数スコープ を参照してください。
Xはどこにありますか?
xは定義されていないので見つかりません。 :-)それを置くと、code1(global)またはcode3(local)にあります。
code2(クラスメンバー)は、同じクラスのメソッド内のコードからは見えません - 通常はselfを使ってそれらにアクセスします。 code4/code5(ループ)はcode3と同じスコープ内にあるので、そこにxを書き込んだ場合、新しいxを作成するのではなく、code3で定義されているxインスタンスを変更することになります。
Pythonは静的スコープなので、 'spam'を別の関数に渡しても、スパムはそれが由来するモジュール(code1で定義されている)やその他のスコープ(下記参照)のグローバルにアクセスすることができます。 code2のメンバーは再びselfを通してアクセスされます。
ラムダはdefと違いはありません。関数内でラムダが使用されている場合は、入れ子関数を定義するのと同じです。 Python 2.2以降では、ネストしたスコープが利用可能です。この場合、関数のネストのどのレベルでもxを束縛することができ、Pythonは最も内側のインスタンスを拾います。
x= 0
def fun1():
x= 1
def fun2():
x= 2
def fun3():
return x
return fun3()
return fun2()
print fun1(), x
2 0
fun3は、最も近い包含スコープ(fun2に関連付けられた関数スコープ)からインスタンスxを見ます。しかし、fun1およびグローバルに定義されている他のxインスタンスは影響を受けません。
Nested_scopesより前のバージョン(Python 2.1以前、および2.1からは、from-future-importを使用して特別に機能を要求しない限り) - fun1とfun2のスコープはfun3には表示されないため、S.Lottの答えが成り立ち、グローバルx :
0 0
Pythonでは、
値が割り当てられた変数は、その割り当てが現れるブロックに対してローカルです。
現在のスコープ内に変数が見つからない場合は、LEGBの順番を参照してください。