はじめに
Pythonを使ってスクリプトを書く際に、「関数の結果をグローバル変数に保存して、他の関数で使いたい」と考えたことはないだろうか?
実際、この方法はよく見かけるが、思わぬ落とし穴にハマることも多い。先日、私がスクリプトを作成していたとき、まさにこの問題に直面した。
コードの意図としては、CSVデータのamount_value
を解析し、適切な数値として保持しようとしたのだが、うまく動作しなかった。
ここでは、私の失敗談を元に、「Pythonで関数の結果をグローバル変数に保存する際の注意点」について解説する。
問題となったコード
まずは、私が書いたスクリプトの抜粋を見てほしい。
金額 = ''
def amount_calc(金額値):
グローバル 金額
if isinstance(金額値, str):
金額値 = 金額値.lower().strip()
if 金額値 == "5以下":
金額 = 5
elif 金額値 == "5以上":
金額 = 10
elif 金額値.isdigit():
金額 = float(金額値)
elif isinstance(金額値, (int, float)):
金額 = int(金額値)
else:
失敗したリクエスト += 1
failed_entries.append(f"\n{address_identifier} - 'amount' の値が無効です")
return 金額
この関数amount_calc()
の目的は、CSVファイルのamount_value
列に含まれるデータを解釈し、適切な数値として保存することだった。"5 以下"
なら5
、"5 以上"
なら10
を割り当て、それ以外は数値に変換する。
しかし、このコードを実行すると、グローバル変数金額
が期待通りに更新されないという問題が発生した。
どこが間違っていたのか?
原因は Pythonのスコープの仕組み にある。
Pythonでは、関数内でグローバル変数を変更したい場合にglobal
キーワードを使う必要がある。しかし、次のような問題がある。
問題点1: グローバル変数の書き換えが意図通りにならない
Pythonのスコープのルールでは、関数内で変数に代入が行われると、それはデフォルトでローカル変数とみなされる。
つまり、以下のコードは、ローカル変数金額
を作成してしまい、グローバル変数金額
には影響を与えない。
def amount_calc(金額値):
if isinstance(金額値, str):
金額 = 5 # ← ここで新しいローカル変数「**金額**」が作られる
これを解決するために、global
キーワードを使用する必要があるのだが、コード内ではglobal 金額
と書いているにもかかわらず、まだ問題がある。
解決策1: globalの正しい使い方
global
キーワードを使用する場合、関数内で変数を明示的にグローバルスコープとして宣言する。
金額 = ''
def amount_calc(金額値):
global 金額 # ← 明示的にグローバル変数を使うと宣言
if isinstance(金額値, str):
金額値 = 金額値.lower().strip()
if 金額値 == "5以下":
金額 = 5
elif 金額値 == "5以上":
金額 = 10
elif 金額値.isdigit():
金額 = float(金額値)
elif isinstance(金額値, (int, float)):
金額 = int(金額値)
else:
失敗したリクエスト += 1
failed_entries.append(f"\n{address_identifier} - 'amount' の値が無効です")
return 金額
この修正により、関数内で金額
を更新すると、それがグローバルスコープの変数にも反映されるようになる。
しかし、これはあまり良い方法ではない。
解決策2: グローバル変数ではなく、戻り値を使う
実は、グローバル変数を使うのは最適解ではない。関数は、結果を返すのが正しい設計だ。Pythonでは、関数の戻り値を使って、呼び出し元で変数に代入する方が安全である。
def amount_calc(金額値):
if isinstance(金額値, str):
金額値 = 金額値.lower().strip()
if 金額値 == "5以下":
return 5
elif 金額値 == "5以上":
return 10
elif 金額値.isdigit():
return float(金額値)
elif isinstance(金額値, (int, float)):
return int(金額値)
else:
失敗したリクエスト += 1
failed_entries.append(f"\n{address_identifier} - 'amount' の値が無効です")
return None # 無効な値の場合はNoneを返す
# 関数を呼び出すときに変数に代入
金額 = amount_calc(row["amount_value"])
この方法なら、グローバル変数を汚さずに済むし、関数が予測可能な動作をするようになる。
まとめ
Pythonでグローバル変数を使うのは一見便利だが、スコープの扱いを間違えると期待通りに動かないことがある。
今回のポイントをまとめると:
✅ グローバル変数を関数内で更新する場合は、global
を明示的に使う必要がある
✅ 関数の戻り値を利用して、グローバル変数に代入する方が安全で一般的
✅ グローバル変数を多用すると、コードの可読性が低下し、デバッグが難しくなる
Pythonの関数設計では、戻り値を適切に使うことがベストプラクティスだ。
もし同じような問題に直面しているなら、グローバル変数を減らす方向でコードを見直してみてほしい。
コメント