このメッセージは少し長く、多くの例がありますが、私や他の人がPython 2.7。
コードブロック(モジュール、クラス定義、関数定義など)にPEP 227( http://www.python.org/dev/peps/pep-0227/ )の用語を使用しています。)および変数バインディング(割り当て、引数宣言、クラスおよび関数宣言、forループなど)
ドットなしで呼び出すことができる名前には変数という用語を使用し、オブジェクト名で修飾する必要がある名前には属性(オブジェクトobjの属性xのobj.xなど)を使用しています。
Pythonにはすべてのコードブロックに対して3つのスコープがありますが、関数は次のとおりです。
Python関数のみ(PEP 227による))には4つのブロックがあります。
変数をバインドしてブロック内で見つけるためのルールは非常に単純です。
このルールを検証し、多くの特殊なケースを示す例を挙げてください。それぞれの例について、私は私の理解を与えます。私が間違っている場合は私を訂正してください。最後の例では、結果がわかりません。
例1:
x = "x in module"
class A():
print "A: " + x #x in module
x = "x in class A"
print locals()
class B():
print "B: " + x #x in module
x = "x in class B"
print locals()
def f(self):
print "f: " + x #x in module
self.x = "self.x in f"
print x, self.x
print locals()
>>>A.B().f()
A: x in module
{'x': 'x in class A', '__module__': '__main__'}
B: x in module
{'x': 'x in class B', '__module__': '__main__'}
f: x in module
x in module self.x in f
{'self': <__main__.B instance at 0x00000000026FC9C8>}
クラスのネストされたスコープ(ルールLGB)はなく、クラス内の関数は、修飾名(この例ではself.x)を使用せずにクラスの属性にアクセスできません。これはPEP227で詳しく説明されています。
例2:
z = "z in module"
def f():
z = "z in f()"
class C():
z = "z in C"
def g(self):
print z
print C.z
C().g()
f()
>>>
z in f()
z in C
ここでは、関数内の変数はLEGBルールを使用して検索されますが、クラスがパスにある場合、クラス引数はスキップされます。ここでも、これがPEP227が説明していることです。
例3:
var = 0
def func():
print var
var = 1
>>> func()
Traceback (most recent call last):
File "<pyshell#102>", line 1, in <module>
func()
File "C:/Users/aa/Desktop/test2.py", line 25, in func
print var
UnboundLocalError: local variable 'var' referenced before assignment
pythonのような動的言語では、すべてが動的に解決されることが期待されます。ただし、これは関数には当てはまりません。ローカル変数はコンパイル時に決定されます。PEP227および http: //docs.python.org/2.7/reference/executionmodel.html この動作をこのように説明します
「コードブロック内のどこかで名前バインディング操作が発生した場合、ブロック内での名前の使用はすべて、現在のブロックへの参照として扱われます。」
例4:
x = "x in module"
class A():
print "A: " + x
x = "x in A"
print "A: " + x
print locals()
del x
print locals()
print "A: " + x
>>>
A: x in module
A: x in A
{'x': 'x in A', '__module__': '__main__'}
{'__module__': '__main__'}
A: x in module
ただし、PEP227のこのステートメントは、「コードブロック内のどこかで名前バインディング操作が発生した場合、ブロック内での名前の使用はすべて、現在のブロックへの参照として扱われる」ことがわかります。コードブロックがクラスの場合は間違っています。さらに、クラスの場合、ローカル名バインディングはコンパイル時ではなく、クラス名前空間を使用した実行中に行われるようです。その点で、PEP227とPythonドキュメントの実行モデルは誤解を招きやすく、一部は間違っています。
例5:
x = 'x in module'
def f2():
x = 'x in f2'
def myfunc():
x = 'x in myfunc'
class MyClass(object):
x = x
print x
return MyClass
myfunc()
f2()
>>>
x in module
このコードについての私の理解は次のとおりです。命令x = xは、最初に式の右側のxが参照しているオブジェクトを検索します。その場合、オブジェクトはクラス内でローカルに検索され、次にルールLGBに従って、グローバルスコープ(モジュール内の文字列 'x')で検索されます。次に、MyClassへのローカル属性xがクラスディクショナリに作成され、文字列オブジェクトを指します。
例6:
これが私が説明できない例です。これは例5に非常に近いもので、ローカルのMyClass属性をxからyに変更しています。
x = 'x in module'
def f2():
x = 'x in f2'
def myfunc():
x = 'x in myfunc'
class MyClass(object):
y = x
print y
return MyClass
myfunc()
f2()
>>>
x in myfunc
その場合、MyClassのx参照が最も内側の関数で検索されるのはなぜですか?
つまり、例5と例6の違いは、例5では変数x
も同じスコープに割り当てられているのに対し、例6には割り当てられていないことです。これにより、履歴で理解できる違いがトリガーされます。理由。
これにより、UnboundLocalErrorが発生します。
x = "foo"
def f():
print x
x = 5
f()
「foo」を出力する代わりに。最初は奇妙に思えても、少し意味があります。関数f()は、印刷後であっても、変数x
をローカルで定義します。同じ関数でのx
への参照は、そのローカル変数への参照である必要があります。少なくとも、グローバル変数の名前を誤ってローカルで再利用し、使用しようとした場合に、奇妙な驚きを回避することは理にかなっていますグローバル変数とローカル変数の両方。これは、変数を見るだけで、それが意味するどの変数を静的に知ることができることを意味するため、良い考えです。たとえば、 print x
がローカル変数を参照していることを知ってください(したがって、UnboundLocalErrorが発生する可能性があります)。
x = "foo"
def f():
if some_condition:
x = 42
print x
f()
現在、このルールはクラスレベルのスコープでは機能しません。そこで、x = x
のような式を機能させ、グローバル変数x
をクラスレベルのスコープにキャプチャします。これは、クラスレベルのスコープが上記の基本的なルールに従わないことを意味します。このスコープのx
が外部変数を参照しているか、ローカルで定義されたx
を参照しているかはわかりません。 - 例えば:
class X:
x = x # we want to read the global x and assign it locally
bar = x # but here we want to read the local x of the previous line
class Y:
if some_condition:
x = 42
print x # may refer to either the local x, or some global x
class Z:
for i in range(2):
print x # prints the global x the 1st time, and 42 the 2nd time
x = 42
したがって、クラススコープでは、別のルールが使用されます。通常はUnboundLocalErrorが発生します---その場合のみ---代わりにモジュールグローバルで検索します。それだけです。ネストされたスコープのチェーンには従いません。
何故なの?私は実際、「歴史的な理由から」というより良い説明があるのではないかと疑っています。より専門的に言えば、変数x
はクラススコープでローカルに定義されている(割り当てられているため)およびはから渡される必要があると考えることができます。字句的にネストされた変数としての親スコープ(読み取られるため)。ローカルスコープで検索するLOAD_NAME
とは異なるバイトコードを使用して実装することは可能であり、見つからない場合はネストされたスコープの参照の使用にフォールバックします。
編集:http://bugs.python.org/issue53286 を参照してくれたwilberforceに感謝します。結局修正する必要があると思われる場合は、提案された新しいバイトコードでディスカッションを再開する機会があるかもしれません(バグレポートではx = x
のサポートを終了することを検討していますが、既存のコードが壊れすぎることを恐れて終了しました;代わりに、ここで提案しているのは、より多くの場合にx = x
を機能させることです)。または私は別の細かい点を見逃しているかもしれません...
EDIT2:CPythonは現在の3.4トランクでそれを正確に実行したようです: http://bugs.python.org/issue1785 = ...かどうか?彼らはわずかに異なる理由でバイトコードを導入し、体系的に使用していません...
理想的な世界では、あなたは正しいでしょうし、あなたが見つけた矛盾のいくつかは間違っているでしょう。ただし、CPythonはいくつかのシナリオ、特に関数ローカルを最適化しました。これらの最適化は、コンパイラと評価ループがどのように相互作用し、歴史的な先例と一緒になって、混乱を招きます。
Pythonはコードをバイトコードに変換し、それらはインタープリターループによって解釈されます。名前にアクセスするための「通常の」オペコードは_LOAD_NAME
_で、辞書の場合と同じように変数名を検索します。 _LOAD_NAME
_は最初に名前をローカルとして検索し、それが失敗した場合はグローバルを検索します。 _LOAD_NAME
_は、名前が見つからない場合にNameError
例外をスローします。
ネストされたスコープの場合、現在のスコープ外の名前の検索はクロージャを使用して実装されます。名前が割り当てられていないが、ネストされた(グローバルではない)スコープで使用できる場合、そのような値はクロージャとして処理されます。これが必要なのは、親スコープが特定の名前に対して異なる時間に異なる値を保持できるためです。親関数を2回呼び出すと、クロージャ値が異なる可能性があります。したがって、Pythonには、その状況に対応する_LOAD_CLOSURE
_、_MAKE_CLOSURE
_、および_LOAD_DEREF
_オペコードがあります。最初の2つのオペコードは、ネストされたスコープのクロージャの読み込みと作成に使用されます。 、および_LOAD_DEREF
_は、ネストされたスコープが必要とするときに、閉じられた値をロードします。
現在、_LOAD_NAME
_は比較的遅いです。 2つの辞書を参照します。つまり、最初にキーをハッシュして、いくつかの同等性テストを実行する必要があります(名前がインターンされていない場合)。名前がローカルでない場合は、グローバルに対してこれを再度実行する必要があります。何万回も呼び出される可能性のある関数の場合、これは面倒な作業になる可能性があります。したがって、関数ローカルには特別なオペコードがあります。ローカル名のロードは、_LOAD_FAST
_によって実装されます。これは、ローカル変数を検索しますインデックスによって特別なローカル名配列で。これははるかに高速ですが、コンパイラは最初に名前がグローバルではなくローカルであるかどうかを確認する必要があります。グローバル名を引き続き検索できるようにするために、別のオペコード_LOAD_GLOBAL
_が使用されます。コンパイラは、この場合を明示的に最適化して、特別なオペコードを生成します。 _LOAD_FAST
_は、名前の値がまだない場合、UnboundLocalError
例外をスローします。
一方、クラス定義本体は関数のように扱われますが、この最適化ステップは実行されません。クラス定義は、それほど頻繁に呼び出されることを意図したものではありません。ほとんどのモジュールは、インポート時にクラスを作成しますonce。クラススコープもネスト時にカウントされないため、ルールはより単純です。その結果、スコープを少し混ぜ始めると、クラス定義本体は関数のようには機能しません。
したがって、非関数スコープの場合、_LOAD_NAME
_と_LOAD_DEREF
_は、それぞれローカルとグローバル、およびクロージャーに使用されます。関数の場合、代わりに_LOAD_FAST
_、_LOAD_GLOBAL
_、および_LOAD_DEREF
_が使用されます。
クラス本体はPythonがclass
行を実行するとすぐに実行されることに注意してください!したがって、例1では、_class B
_内の_class A
_が_class A
_とすぐに実行されます。モジュールをインポートするときに実行されます。例2では、C
は、前ではなく、f()
が呼び出されるまで実行されません。
あなたの例を見てみましょう:
クラス_A.B
_をクラスA
にネストしました。クラス本体はネストされたスコープを形成しないため、クラスA
の実行時に_A.B
_クラス本体が実行されても、コンパイラは_LOAD_NAME
_を使用してx
を検索します。 A.B().f()
はfunction(メソッドとしてB()
インスタンスにバインドされている)であるため、_LOAD_GLOBAL
_を使用してx
をロードします。ここでは属性アクセスを無視します。これは非常に明確に定義された名前パターンです。
ここで、f().C.z
はクラススコープにあるため、関数f().C().g()
はC
スコープをスキップし、代わりに_LOAD_DEREF
_を使用してf()
スコープを調べます。
ここで、var
は、スコープ内で割り当てるため、コンパイラーによってローカルであると判断されました。関数が最適化されているため、_LOAD_FAST
_を使用してローカルを検索し、例外がスローされます。
今、物事は少し奇妙になります。 _class A
_はクラススコープで実行されるため、_LOAD_NAME
_が使用されています。スコープのローカルディクショナリから_A.x
_が削除されたため、x
への2回目のアクセスにより、代わりにグローバルx
が検出されます。 _LOAD_NAME
_は最初にローカルを検索しましたが、そこで見つかりませんでした。グローバルルックアップにフォールバックしました。
はい、これはドキュメントと矛盾しているようです。 Python-the-languageとCPython-実装はここで少し衝突しています。しかし、あなたは動的言語で可能で実用的なものの限界を押し広げています。 x
が_LOAD_NAME
_のローカルである必要があるかどうかを確認することは可能ですが、ほとんどの開発者が遭遇することのないコーナーケースには貴重な実行時間がかかります。
今、あなたはコンパイラを混乱させています。クラススコープで_x = x
_を使用したため、スコープ外の名前からlocalを設定しています。コンパイラーは、x
がここでローカルである(ユーザーが割り当てた)ことを検出するため、スコープ名である可能性があるとは見なしません。これは最適化された関数本体ではないため、コンパイラーは、このスコープ内のx
へのすべての参照に_LOAD_NAME
_を使用します。
クラス定義を実行するとき、_x = x
_は最初にx
を検索する必要があるため、_LOAD_NAME
_を使用して実行します。 x
が定義されておらず、_LOAD_NAME
_がローカルを見つけられないため、globalx
が見つかります。結果の値はローカルとして保存され、happensもx
という名前になります。 _print x
_は再び_LOAD_NAME
_を使用し、新しいローカルx
値を見つけます。
ここでは、コンパイラを混乱させませんでした。ローカルy
を作成していますが、x
はローカルではないため、コンパイラはそれを親関数f2().myfunc()
からのスコープ名として認識します。 x
はクロージャから_LOAD_DEREF
_で検索され、y
に格納されます。
私の意見では修正する価値はありませんが、5と6の間の混乱はバグとして見ることができます。それは確かにそのように提出されました。Pythonバグトラッカーの issue 53286 を参照してください、それは10年以上前から存在しています。
コンパイラは、例5の最初の割り当てで、x
がalso localの場合でも、スコープ名x
をチェックできます。または_LOAD_NAME
_は、名前がローカルであるかどうかをチェックできます。実際には、パフォーマンスを犠牲にして、ローカルが見つからなかった場合はUnboundLocalError
をスローします。これが関数スコープ内にあった場合、たとえば5では_LOAD_FAST
_が使用され、UnboundLocalError
がすぐにスローされます。
ただし、参照されているバグが示すように、歴史的な理由から、動作は保持されます。このバグが修正されれば壊れてしまうコードが今日そこにあるでしょう。
簡単に言えば、これはPythonのスコープのコーナーケースであり、少し一貫性がありませんが、下位互換性のために保持する必要があります(そして、正しい答えが何であるかが明確ではないため)。 Python PEP227が実装されていたときのメーリングリストでそれについての 元の議論 の多くを見ることができます バグ のいくつかこの動作が修正されます。
dis
モジュールを使用すると、違いがある理由を理解できます。このモジュールを使用すると、コードオブジェクトの内部を調べて、コードの一部がコンパイルされたバイトコードを確認できます。私はPython 2.6を使用しているので、これの詳細は少し異なるかもしれません-しかし、同じ動作が見られるので、おそらく2.7に十分近いと思います。
ネストされた各MyClass
を初期化するコードは、最上位関数の属性を介してアクセスできるコードオブジェクトに存在します。 (関数の名前を例5と例6からそれぞれf1
とf2
に変更しています。)
コードオブジェクトにはco_consts
タプルがあり、これにはmyfunc
コードオブジェクトが含まれています。このタプルには、MyClass
が作成されたときに実行されるコードが含まれています。
In [20]: f1.func_code.co_consts
Out[20]: (None,
'x in f2',
<code object myfunc at 0x1773e40, file "<ipython-input-3-6d9550a9ea41>", line 4>)
In [21]: myfunc1_code = f1.func_code.co_consts[2]
In [22]: MyClass1_code = myfunc1_code.co_consts[3]
In [23]: myfunc2_code = f2.func_code.co_consts[2]
In [24]: MyClass2_code = myfunc2_code.co_consts[3]
次に、dis.dis
を使用してバイトコードでそれらの違いを確認できます。
In [25]: from dis import dis
In [26]: dis(MyClass1_code)
6 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
7 6 LOAD_NAME 2 (x)
9 STORE_NAME 2 (x)
8 12 LOAD_NAME 2 (x)
15 PRINT_ITEM
16 PRINT_NEWLINE
17 LOAD_LOCALS
18 RETURN_VALUE
In [27]: dis(MyClass2_code)
6 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
7 6 LOAD_DEREF 0 (x)
9 STORE_NAME 2 (y)
8 12 LOAD_NAME 2 (y)
15 PRINT_ITEM
16 PRINT_NEWLINE
17 LOAD_LOCALS
18 RETURN_VALUE
したがって、唯一の違いは、MyClass1
ではx
がLOAD_NAME
opを使用してロードされるのに対し、MyClass2
ではLOAD_DEREF
を使用してロードされることです。 LOAD_DEREF
は、囲んでいるスコープで名前を検索するため、「x inmyfunc」を取得します。 LOAD_NAME
はネストされたスコープに従いません-x
またはf1
でバインドされたmyfunc
名を確認できないため、モジュールレベルのバインドを取得します。
次に、問題は、2つのバージョンのMyClass
のコードが2つの異なるオペコードにコンパイルされるのはなぜですか。 f1
では、バインディングはクラススコープのx
をシャドウイングしていますが、f2
では新しい名前をバインディングしています。 MyClass
スコープがクラスではなくネストされた関数である場合、y = x
のf2
行は同じようにコンパイルされますが、x = x
のf1
は次のようになります。 LOAD_FAST
-これは、コンパイラがx
が関数にバインドされていることを認識しているため、LOAD_FAST
を使用してローカル変数を取得する必要があるためです。これは、呼び出されたときにUnboundLocalError
で失敗します。
In [28]: x = 'x in module'
def f3():
x = 'x in f2'
def myfunc():
x = 'x in myfunc'
def MyFunc():
x = x
print x
return MyFunc()
myfunc()
f3()
---------------------------------------------------------------------------
Traceback (most recent call last)
<ipython-input-29-9f04105d64cc> in <module>()
9 return MyFunc()
10 myfunc()
---> 11 f3()
<ipython-input-29-9f04105d64cc> in f3()
8 print x
9 return MyFunc()
---> 10 myfunc()
11 f3()
<ipython-input-29-9f04105d64cc> in myfunc()
7 x = x
8 print x
----> 9 return MyFunc()
10 myfunc()
11 f3()
<ipython-input-29-9f04105d64cc> in MyFunc()
5 x = 'x in myfunc'
6 def MyFunc():
----> 7 x = x
8 print x
9 return MyFunc()
UnboundLocalError: local variable 'x' referenced before assignment
MyFunc
関数がLOAD_FAST
を使用するため、これは失敗します。
In [31]: myfunc_code = f3.func_code.co_consts[2]
MyFunc_code = myfunc_code.co_consts[2]
In [33]: dis(MyFunc_code)
7 0 LOAD_FAST 0 (x)
3 STORE_FAST 0 (x)
8 6 LOAD_FAST 0 (x)
9 PRINT_ITEM
10 PRINT_NEWLINE
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
(余談ですが、スコープがクラスの本体のコードと関数のコードと相互作用する方法に違いがあるはずです。クラスレベルのバインディングはメソッドで使用できないため、これを知ることができます-メソッドスコープは、ネストされた関数と同じようにクラススコープ内にネストされません。クラスを介して、またはself.
を使用して明示的にメソッドスコープに到達する必要があります(これも存在しない場合はクラスにフォールバックしますインスタンスレベルのバインディング))。