編集:
この質問の最後にある私の完全な回答をご覧ください。
tl; dr answer:Pythonには静的にネストされたスコープがあります。静的の態様は、非自明な結果が得られ、暗黙変数宣言と相互作用することができます。
(これは、言語が一般的に動的な性質を持つため、特に驚くべきことです)。
私はPythonのスコープルールをかなりうまく処理できたと思いましたが、この問題は私を完全に妨げてしまい、google-fuが失敗しました(驚いたわけではありません-質問のタイトルを見てください;)
期待どおりに機能するいくつかの例から始めますが、ジューシーな部分については例4に進んでください。
例1。
>>> x = 3
>>> class MyClass(object):
... x = x
...
>>> MyClass.x
3
単純明快:クラスの定義中に、外部(この場合はグローバル)スコープで定義された変数にアクセスできます。
例2。
>>> def mymethod(self):
... return self.x
...
>>> x = 3
>>> class MyClass(object):
... x = x
... mymethod = mymethod
...
>>> MyClass().mymethod()
3
繰り返しますが(今のところ、これを実行する理由を無視します)、ここでは予期しないことは何もありません。外側のスコープの関数にアクセスできます。
注:フレデリックが下で指摘したように、この関数は機能していないようです。代わりに例5(以降)を参照してください。
例3。
>>> def myfunc():
... x = 3
... class MyClass(object):
... x = x
... return MyClass
...
>>> myfunc().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in myfunc
File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
これは基本的に例1と同じです。クラス定義内から外部スコープにアクセスしていますが、今回はそのスコープがグローバルではないためmyfunc()
です。
編集5:として@ user3022222は、以下の指摘、私は私の元の投稿でこの例をしくじりました。(このクラス定義のような他のコードブロックではなく)関数のみが、外側のスコープの変数にアクセスできるため、これは失敗すると思います。非関数コードブロックの場合、アクセスできるのはローカル変数、グローバル変数、および組み込み変数のみです。この質問では、より完全な説明が利用可能です
もう1つ:
例4。
>>> def my_defining_func():
... def mymethod(self):
... return self.y
... class MyClass(object):
... mymethod = mymethod
... y = 3
... return MyClass
...
>>> my_defining_func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_defining_func
File "<stdin>", line 5, in MyClass
NameError: name 'mymethod' is not defined
えっと…すみません?
例2と何が違うのですか?
私は完全に困惑しています。整理してください。ありがとう!
PSは、これが私の理解の問題ではないという偶然に、Python 2.5.2とPython 2.6.2で試してみました。残念ながら、現時点ではこれらすべてにアクセスできますが、どちらも同じ動作を示します。
編集によるhttp://docs.python.org/tutorial/classes.html#python-scopes-and-namespaces:実行中の任意の時点で、その名前空間に直接アクセス可能な少なくとも三つのネストされたスコープがあります。
#4。これらの2番目の反例のようです。
編集2
例5。
>>> def fun1():
... x = 3
... def fun2():
... print x
... return fun2
...
>>> fun1()()
3
編集3
@Frédéricが指摘したように、外部スコープにあるのと同じ名前の変数への割り当ては、外部変数を「マスク」して、割り当てが機能しないように思われます。
したがって、この変更された例4のバージョンは機能します。
def my_defining_func():
def mymethod_outer(self):
return self.y
class MyClass(object):
mymethod = mymethod_outer
y = 3
return MyClass
my_defining_func()
しかし、これはしません:
def my_defining_func():
def mymethod(self):
return self.y
class MyClass(object):
mymethod_temp = mymethod
mymethod = mymethod_temp
y = 3
return MyClass
my_defining_func()
私はまだこのマスキングが発生する理由を完全に理解していません:割り当てが発生したときに名前バインディングが発生するべきではありませんか?
この例は、少なくともいくつかのヒント(およびより有用なエラーメッセージ)を提供します。
>>> def my_defining_func():
... x = 3
... def my_inner_func():
... x = x
... return x
... return my_inner_func
...
>>> my_defining_func()()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_inner_func
UnboundLocalError: local variable 'x' referenced before assignment
>>> my_defining_func()
<function my_inner_func at 0xb755e6f4>
したがって、ローカル変数は関数の作成時に定義され(成功)、ローカル名が「予約」され、関数が呼び出されたときに外部スコープ名がマスクされるように見えます。
面白い。
フレデリックの回答に感謝します!
参考までに、python docsから:
スコープはテキストで決定されることを理解することが重要です。モジュールで定義された関数のグローバルスコープは、関数が呼び出される場所やエイリアスに関係なく、そのモジュールの名前空間です。一方、名前の実際の検索は実行時に動的に行われますが、言語定義は「コンパイル」時に静的な名前解決に向けて進化しているため、動的な名前解決に依存しないでください。(実際、ローカル変数はすでに静的に決定されています。)
編集4
この一見混乱する動作は、PEP 227で定義されているPythonの静的にネストされたスコープが原因です。実際には、PEP 3104とは関係ありません。
PEP 227から:
名前解決規則は、静的スコープの言語で一般的です[...] [except]変数は宣言されていません。名前バインディング操作が関数のどこかで発生した場合、その名前は関数のローカルとして扱われ、すべての参照はローカルバインディングを参照します。名前がバインドされる前に参照が発生すると、NameErrorが発生します。
[...]
Tim Petersの例は、宣言がない場合のネストされたスコープの潜在的な落とし穴を示しています。
i = 6 def f(x): def g(): print i # ... # skip to the next page # ... for i in x: # ah, i *is* local to f, so this is what g sees pass g()
g()の呼び出しは、forループによってf()でバインドされた変数iを参照します。ループが実行される前にg()が呼び出されると、NameErrorが発生します。
Timの例の2つの簡単なバージョンを実行してみましょう。
>>> i = 6
>>> def f(x):
... def g():
... print i
... # ...
... # later
... # ...
... i = x
... g()
...
>>> f(3)
3
が内部スコープでg()
見つからない場合i
、動的に外側を検索し、割り当てを通じてバインドされているi
in f
のスコープを見つけます。3
i = x
ただし、最後の2つのステートメントの順序を変更するf
と、エラーが発生します。
>>> i = 6
>>> def f(x):
... def g():
... print i
... # ...
... # later
... # ...
... g()
... i = x # Note: I've swapped places
...
>>> f(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in f
File "<stdin>", line 3, in g
NameError: free variable 'i' referenced before assignment in enclosing scope
PEP 227が「名前解決規則は静的スコープ言語の典型である」と述べたことを思い出して、(準)同等のCバージョンのオファーを見てみましょう:
// nested.c
#include <stdio.h>
int i = 6;
void f(int x){
int i; // <--- implicit in the python code above
void g(){
printf("%d\n",i);
}
g();
i = x;
g();
}
int main(void){
f(3);
}
コンパイルして実行:
$ gcc nested.c -o nested
$ ./nested
134520820
3
したがって、Cはバインドされていない変数を(喜んで以前にそこに格納されていたものを使用して)使用しますが、Pythonは(ありがたいことに)拒否します。
興味深い補足として、静的にネストされたスコープは、Alex Martelliが「Pythonコンパイラーが行う単一の最も重要な最適化:関数のローカル変数はdictに保持されず、値のタイトなベクトルにあり、ローカル変数アクセスは、名前の検索ではなく、そのベクトルのインデックスを使用します。」
これはPythonの名前解決ルールの成果物です。 グローバルスコープとローカルスコープにのみアクセスでき、中間のスコープにはアクセスできません。たとえば、すぐ外側のスコープにはアクセスできません。
EDIT:上記の悪い言葉で表現された、あなたがやる外側のスコープで定義された変数へのアクセス権を持っていますが、実行してx = x
またはmymethod = mymethod
非グローバル名前空間から、あなたが実際にあなたがローカルに定義している1と外側の変数をマスキングしています。
例2では、直接外側のスコープはグローバルスコープであるため、MyClass
を表示できますmymethod
が、例4では、直接外側のスコープはでありmy_defining_func()
、そうすることはできませんmymethod
。
非ローカル名前解決の詳細については、PEP 3104を参照してください。
また、上記の理由により、例3をPython 2.6.5または3.1.2で実行することはできません。
>>> def myfunc():
... x = 3
... class MyClass(object):
... x = x
... return MyClass
...
>>> myfunc().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in myfunc
File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
しかし、以下はうまくいきます:
>>> def myfunc():
... x = 3
... class MyClass(object):
... y = x
... return MyClass
...
>>> myfunc().y
3
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加