グローバル変数の扱い

Pythonのプログラムにおいて、変数がどこから読み書きできるかという「有効範囲」のことをスコープと呼びます。
その中でも、関数の外側(プログラムの一番上の階層)で定義され、プログラム全体からアクセスできる変数のことをグローバル変数と呼びます。非常に便利な仕組みである反面、使い方を誤ると予期せぬバグの温床になりやすいため、適切な管理が必要です。本記事では、その正しい扱い方について徹底解説します。
グローバル変数の基本(値の参照)
グローバル変数は、プログラム内のどこからでも、そしてどの関数の中からでも自由に「値の読み込み(参照)」を行うことができます。
# 関数の外側(最上階層)で定義されたグローバル変数
x = 100
def show_value():
# 関数の中から外側のグローバル変数を読み込む
print(x) # 出力: 100
show_value()
このコードでは、関数 show_value 内に変数の定義がありませんが、Pythonは自動的に外側のグローバルスコープを探しに行き、変数 x の値である 100 を正しく読み取って表示します。
グローバル変数の変更(globalキーワード)
先ほどとは異なり、関数の中でグローバル変数の「値の書き換え(変更)」を行いたい場合は注意が必要です。Pythonでは、関数内で普通に変数を上書きしようとすると、同名の新しい「ローカル変数」がその場に作られてしまう仕様になっているためです。
関数内から本物のグローバル変数を書き換えるには、global キーワードを使って明示的に宣言する必要があります。
x = 100 # グローバル変数
def modify_value():
# 【超重要】この関数内の x は、外のグローバル変数のことであると宣言
global x
x = 200 # グローバル変数を上書き
print(f"関数内のx: {x}") # 出力: 200
modify_value()
print(f"関数外のx: {x}") # 出力: 200(関数外でも値が書き換わっている)
上記のコードの解説は以下の通りです。
global xと記述することで、Pythonに対して「これ以降、この関数内でxという名前が登場したら、それはローカル変数ではなく、外にあるグローバル変数のことだよ」と教えることができます。- その後に
x = 200とすることで、関数を抜けた後もプログラム全体でxの値が200に上書きされ続けます。
【初心者の落とし穴】globalを忘れたときに起きる不具合
もし global 宣言を忘れて関数内で値を書き換えようとすると、どのような問題が起きるかを実例で確認しましょう。
x = 100 # グローバル変数
def incorrect_modify():
# global宣言を忘れた状態
x = 200 # 💡Pythonは「関数内だけで使う新しいローカル変数x」を作ったと解釈する
print(f"関数内のx: {x}") # 出力: 200
incorrect_modify()
print(f"関数外のx: {x}") # 出力: 100(外側のグローバル変数は100のまま変わっていない!)
このように、global キーワードを書き忘れると、外側の変数と名前が同じなだけの「別人の変数(ローカル変数)」が内部で勝手に誕生してしまいます。その結果、関数の中では値が変わっているのに外に出ると元に戻っている、という極めて気づきにくいバグを引き起こす原因になります。
グローバル変数とローカル変数の違い
2つの変数の性質やルールの決定的な違いのまとめです。
| 項目 | グローバル変数 | ローカル変数 |
|---|---|---|
| 定義される場所 | 関数の外側(トップレベル) | 関数の内側 |
| 有効な範囲(寿命) | プログラムが起動してから終了するまで全体 | その関数が呼び出されてから、処理が終わるまで |
| 関数内での変更方法 | global 変数名 という明示的な宣言が必須 |
事前の宣言なしで、自由に書き換え可能 |
実務における注意点と「グローバル変数を使わない」設計思想
プログラミングの世界では、「グローバル変数の多用は原則として避けるべき(悪手)」とされています。理由は以下の3点にあります。
- バグの原因追跡が困難になる:あらゆる関数から値を書き換えられてしまうため、「いつの間にか数値がおかしくなっている」というバグが起きた際、どの関数が犯人なのかを特定するのが非常に難しくなります。
- コードの再利用性が下がる:特定のグローバル変数に依存した関数は、他のプログラムにコピペして使い回すことができなくなります。
そのため、実務ではグローバル変数の代わりに、以下のような安全なアプローチをとることが強く推奨されます。
# 推奨される設計:データの受け渡しは「引数」と「戻り値」で行う
def calculate_next_score(current_score):
# 必要なデータは引数で受け取る
new_score = current_score + 50
# 結果は戻り値として安全に外へ送り返す
return new_score
score = 100
# 関数を呼び出して結果をスマートに受け取る
score = calculate_next_score(score)
print(score) # 出力: 150
まとめ
- どこからでも読めるグローバル変数:関数の外で定義された変数は、プログラム全体から参照(読み込み)することができます。
- 変更には
global宣言が必須:関数内部からグローバル変数の値を書き換えたい場合は、必ずglobal 変数名と宣言しなければなりません。宣言を忘れると同名のローカル変数が作られてしまいます。 - 引数と戻り値による対話を優先する:グローバル変数はプログラムの可読性を下げてしまうリスクがあるため、原則として「関数への引数渡し」と「
returnによる結果の返却」を用いたクリーンな設計を徹底しましょう。