pythonスコープルールを理解しようとすると、ひどい問題が発生します。
次のスクリプトを使用します。
a = 7
def printA():
print "Value of a is %d" % (a)
def setA(value):
a = value
print "Inside setA, a is now %d" %(a)
print "Before setA"
printA()
setA(42)
print "After setA"
printA()
次の予期しない(私にとっての)出力を提供します。
setA の前aの値は7 setA内では、aは42 setA の後aの値は7 [.____。です。 ]
Aの値の最後の出力が7ではなく42になると予想される場合、グローバル変数のスコープに関するPythonのスコープルールについて何が欠けていますか?
グローバル変数は特別です。変数に割り当てようとするとa = value
関数内では、同じ名前のグローバル変数が存在する場合でも、関数内に新しいローカル変数を作成します。代わりにグローバル変数にアクセスするには、関数内に global
ステートメント を追加します。
a = 7
def setA(value):
global a # declare a to be a global
a = value # this sets the global value of a
Pythonの命名規則とバインディング規則の詳細な説明については、 命名とバインディング も参照してください。
これを理解する秘trickは、=を使用して変数に代入するときに、それをローカル変数としても宣言することです。したがって、グローバル変数aの値を変更する代わりに、setA(value)は実際にローカル変数(たまたまaと呼ばれる)を渡された値に設定します。
これは、次のようにsetA(value)の先頭でaの値を出力しようとすると、より明白になります。
def setA(value):
print "Before assignment, a is %d" % (a)
a = value
print "Inside setA, a is now %d" % (a)
このPythonを実行しようとすると、役立つエラーが表示されます。
トレースバック(最後の最後の呼び出し): ファイル「scopeTest.py」、14行目、 setA(42) ファイル「scopeTest.py」、 7行目、setA で「割り当て前、aは%d」を出力%(a) UnboundLocalError:割り当て前に参照されたローカル変数 'a'
これは、PythonがsetA(value)関数にaというローカル変数があることを決定したことを示しています。これは、関数で割り当てたときに変更するものです。関数内のa(printA()と同様)の場合、Pythonはグローバル変数Aを使用します。
変数をグローバルとしてマークするには、Pythonでglobalキーワードグローバル変数を使用するスコープ内を使用する必要があります。この場合、setA(value)関数内にあります。したがって、スクリプトは次のようになります。
a = 7
def printA():
print "Value of a is %d" % (a)
def setA(value):
global a
a = value
print "Inside setA, a is now %d" %(a)
print "Before setA"
printA()
setA(42)
print "After setA"
printA()
この1行の追加により、Python setA(value)関数で変数aを使用すると、ローカル変数ではなくグローバル変数について話していることがわかります。
Pythonには、他の言語のような変数の概念がありません。 「どこかに」あるオブジェクトがあり、これらのオブジェクトへの参照があります。 =は、これらのオブジェクトをcurrent名前空間の参照に割り当てるために使用されます。
値が参照するオブジェクトを参照するsetA関数の名前空間に名前aを作成します。
関数内で、aはローカル変数として扱われます。定義する必要があります
グローバルな
関数内
関数を実行すると、関数のローカル変数に使用される新しいシンボルテーブルが導入されます。より正確には、関数内のすべての変数の割り当ては、ローカルシンボルテーブルに値を格納します。一方、変数参照は、最初にローカルシンボルテーブル、次に囲んでいる関数のローカルシンボルテーブル、次にグローバルシンボルテーブル、最後に組み込み名のテーブルを調べます。したがって、グローバル変数は、参照される場合もありますが、関数内で値を直接割り当てることはできません(グローバルステートメントで名前が付けられている場合を除く)。