Pythonで関数の結果をグローバル変数に保存する方法とその落とし穴

プログラミング

はじめに

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の関数設計では、戻り値を適切に使うことがベストプラクティスだ。
もし同じような問題に直面しているなら、グローバル変数を減らす方向でコードを見直してみてほしい。

コメント