【python】pythonにおけるスコープ【グローバル変数】
pythonでは変数のスコープに最新の注意を払う必要があり、特に万一グローバル変数(厳密にはスコープはモジュール内に収まるので、モジュール変数?)の変更を扱うような場合、気を緩めていると下のコードに示すような問題を引き起こす可能性があります。
is_odd = False def check_odd(value): if value % 2 == 1: # 書き換え(たつもり) is_odd = True check_odd(1) print(is_odd) # False(Trueではない)
のような問題が起こります。
問題はランタイムがこれを正常なコードとして解釈できてしまうことで(当然ですが)、check_odd
内でのグローバル変数is_odd
の書き換え(たつもり)処理は単なるcheck_odd
中のローカル変数is_odd
定義に終わります。なのでグローバル変数のis_odd
に変化はありません。
global
修飾子を使えば、一応所望の結果を得ることができます。
is_odd = False def check_odd(value): global is_odd # グローバルなis_oddを参照 if value % 2 == 1: # グローバルなis_oddを書き換え is_odd = True check_odd(1) print(is_odd) # True
ただ身も蓋もないことを言ってしまうと、個人的にはこのようなグローバル領域に変数を置くこと自体避けるべきと考えます。上記のような副作用を防ぐ意図だけでなく、変数=状態の変遷という意味でも、特別なことがない限り変数はオブジェクトに管理させるべきです。
グローバル領域には、基本的に定数扱いの変数のみを置くべきだと思います。
# ホントはmathやnumpyのπやexpの使用を推奨 PI = 3.141592 NAPIER = 2.718281828459045 def gaussian(x, mu, sigma): return 1 / ((2 * PI) ** 0.5 * sigma) * (NAPIER ** ( - (x - mu) ** 2 / (2 * sigma * sigma))) print(sum([gaussian(i, 0, 1) for i in range(-100,100)])) #1.000000109372639
前述の通り、pythonではglobal
修飾子を明示的につけない限り、変数への代入記述はローカル変数に対するものと解釈されます。なのでglobal
と書かなければ故意にグローバル変数を書き換えてしまうことはありません。仮にグローバル変数=定数という規約のもと、グローバル変数と同じ名前の変数への代入をより小さなスコープ内で行った場合、それはそのスコープ内での変数定義となります。
ちなみに変数の参照時には、最も内側のスコープから外側へと同名の変数を探索します(それでもなかったら、Build-Inの変数を参照します)。すなわち同一スコープ内に定義がされてない場合、勝手に外側のスコープ内の変数が参照されます。そのためグローバル変数は参照するだけならglobal
修飾子を必要としません。