Pythonの役割ドメイン(zz)


Pythonの役割ドメイン
1年前に発表された(2013-01-05 17:37)読書(
218)|コメント(
0) 
6人はこの文章を収集して、私は収集します
賛0
(1)最もネストされた役割ドメイン規則:1つの付与文によって導入された名前は、この付与文が存在する役割ドメインで表示(機能)され、内部にネストされた各役割ドメインでも表示されます.内部にネストされていない限り、同じ名前を導入した別の付与文がマスク/上書きされます.(2)LEGB:シンボルテーブルの検索順はLocal->Enclosing Function->Global->Built-in
たとえば、次の例でエラーが発生します.01 >>> x = 10 02 >>>  def   f(): 03   ...    print (x) 04   ...   x + = 1 05
  06   >>> f() 07     Traceback (most recent call last): 08     File   "" , line  1 in   :     f() 09     File   "" , line  2 in   f :     print (x) 10     UnboundLocalError: local variable  'x'   referenced before assignment 11 >>>
どうして間違えたの?関数f()に変数x+=1が現れるため、コンパイラはxがローカル変数(local)に属すると判断し、LEGBルールに従って先にlocal変数を検索するとprint(x)文の場合、ローカル変数xはまだ値を付けていないため、以下のヒント情報が現れる:UnboundLocalError:local variable'x'referenced before assignment
からhttp://blog.sina.com.cn/s/blog_7e4ac8b501015opb.html
Pythonは静的役割ドメイン言語ですが、それ自体は動的言語です.すなわち,Pythonにおける変数の役割ドメインはソースコードにおけるその位置によって決定されるが,これはCと少し似ているが,PythonとCの役割ドメインの違いは非常に明らかである.
次にPythonの役割ドメインルールについてお話ししますが、その中でもPythonとCの役割ドメインの違いについて説明します.
Python 2.0以降のバージョンでは、Pythonは3つの役割ドメイン、すなわちローカル役割ドメイン、グローバル役割ドメイン、内蔵役割ドメインしかサポートしていません.Python 2.2では、Pythonが新しい役割ドメインであるネストされた役割ドメインを正式に導入した.Python 2.1では、ネストされた役割ドメインはオプションとしてオンにすることができる.ネストされた役割ドメインの導入は,本質的にPythonに対して閉パケットのサポートを実現しているが,閉パケットに関する知識は,ネット上で多くの解釈があり,ここでは詳細に展開しない.従って、変数検索順は、前のLGBからLEGB(L:Local,E:Enclosing,G:Global,B:Built-in)となる.
Pythonでは、どのコードブロックでも新しい役割ドメインを導入できるわけではありません.これはCとは大きく異なります.
#include int main() {     if(2 > 0) {         int i = 0;
    }
    printf("i = %d", i);     return 0;
}

このコードではif句にローカル役割ドメインが導入され、変数iはこのローカル役割ドメインに存在するが、外部には見えないため、printf関数での変数iの参照がコンパイルエラーを引き起こす.
しかし、Pythonではそうではありません.
if True:
    i = 0 print i

このコードではif句は局所的な役割ドメインを導入しておらず、変数iは依然としてグローバルな役割ドメインに存在するため、変数iは次のprint文に対して可視である.
実際,Pythonではモジュール,クラスおよび関数のみが新しい役割ドメインを導入し,他のコードブロックは新しい役割ドメインを導入しない(forなども新しい役割ドメインを導入するが,後述する).
Pythonでは、変数を使用する前に事前に宣言する必要はありませんが、実際に使用する前に、オブジェクトにバインドされている必要があります.一方、名前バインドは、現在の役割ドメインで発生している場所にかかわらず、外層役割ドメインの同名変数をマスクしながら、現在の役割ドメインに新しい変数を導入します. 
def f(): print i
f()

実行結果は、NameError:global name'i'is not definedと表示されます.Pythonはまず関数fのローカル役割ドメインで変数iを検索し、検索に失敗し、次にグローバル役割ドメインと内蔵役割ドメインで変数iを検索したが、依然として失敗し、最終的にNameError異常を投げ出した.
i = 0 def f():
    i = 8 print i
f() print i

実行結果:8と0が表示されます.i=8は、関数fのローカル役割ドメインに新しい変数iを導入し、グローバル変数iを遮蔽する名前バインド操作であるため、f内部のprint文はローカル変数i、f外部のprint文はグローバル変数iを見る.
i = 0 def f(): print i
    i = 0
f()

実行結果:UnboundLocalError:local variable'i'referenced before assignment.この例では、関数fの変数iは局所変数であるが、print文がそれを使用する場合、まだ任意のオブジェクトにバインドされていないため、異常が投げ出される.
print i
i = 0

インタラクティブに実行しても、スクリプトファイルで実行しても、結果はName Error:name'i'is not definedと表示されます.ここでの出力結果は、トップレベルの役割ドメイン(モジュール役割ドメイン)にあるため、前の例とは異なる.モジュールコードでは、コードは実行前に何も前処理されていませんが、関数体では、コードは実行前に前処理されているので、名前バインドが役割ドメインの位置で発生しても感知できます.Pythonは静的役割ドメイン言語ですが、名前検索は確かに動的に発生するため、実行するまで名前の問題が発見されません.
Pythonでは、名前バインドが属する役割ドメインに新しい変数を導入し、オブジェクトにバインドします.名前バインドは、次のような場合に発生します.
    1.パラメータ宣言:パラメータ宣言は、関数のローカル役割ドメインに新しい変数を導入します.
    2.付与アクション:1つの変数に対して初回付与を行うと、現在の役割ドメインに新しい変数が導入され、後続の付与アクションで変数が再バインドされます.
    3.クラスと関数の定義:クラスと関数の定義はクラス名と関数名を変数として現在の役割ドメインに導入し、クラス体と関数体は別の役割ドメインを形成します.
    4.import文:import文は現在の役割ドメインに新しい変数を導入し、一般的にグローバル役割ドメインである.
    5.for文:for文は現在の役割ドメインに新しい変数(ループ変数)を導入します.
    6.Except文:except文は、現在の役割ドメインに新しい変数(例外オブジェクト)を導入します.
Pythonでは、クラス定義に導入された役割ドメインはメンバー関数には表示されません.これはC++またはJavaとは異なります.したがって、Pythonでは、メンバー関数がクラス定義の変数を参照するにはselfまたはクラス名で参照する必要があります.
ネストされた役割ドメインの追加により、いくつかのコードがコンパイルされないか、異なる実行結果が得られます.ここでPython解釈器は、これらの問題を引き起こす可能性がある場所を識別し、警告を与えるのに役立ちます.
locals関数はすべてのローカル変数を返しますが、ネストされた役割ドメインの変数は返されません.実際にはネストされた役割ドメインの変数を返す関数はありません.
参照先:
    http://www.python.org/dev/peps/pep-0227/
    http://beastie.cs.ua.edu/cs150/book/book_13.html
    http://www-inst.eecs.berkeley.edu/~selfpace/cs9honline/Q2/scope.html
    http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/