スポンサーリンク

Python初心者がハマる設計ミス|グローバル変数が招く不具合の正体

Python入門

「最初はちゃんと動いていたのに、少し処理を足しただけで急にバグが増えた」 「どこで値が変わったのか分からなくて、修正が怖い」 そんな状態に心当たりはありませんか?

Python初心者がスクリプトを書いていく中で、ほぼ確実に一度は通るのが グローバル変数への依存です。

関数の外に変数を置けば、どこからでも参照・変更できて便利。 最初は「楽な書き方」に見えますよね。 でも、スクリプトの行数が増えたあたりから、

  • 修正すると別の場所が壊れる
  • 原因が追えずデバッグに時間がかかる
  • 怖くて手を入れられなくなる

こんな状態に変わっていきます。

実はこれ、Pythonが難しいからではありません。 「設計の考え方」を知らないまま書き続けた結果なんです。

この記事では、

  • Pythonにおけるグローバル変数の正体
  • なぜ初心者ほど依存しやすいのか
  • どう書き直せば安全で壊れにくくなるのか

を、できるだけ専門用語を噛み砕きながら解説していきます。

「グローバル変数は悪だから禁止」という話ではありません。 どこまでが危険で、どこからなら許容できるのか。 その判断ができるようになることがゴールです。

最近スクリプトが壊れ始めたと感じているなら、 今がちょうど「一段成長するタイミング」かもしれません。 一緒に整理していきましょう 🙂


結論:グローバル変数依存の本当の問題は「データの流れが見えないこと」

Pythonのグローバル変数が危険と言われる理由は、 「使うと即バグるから」ではありません。

本質的な問題は、データがどこから来て、どこで変わり、どこへ行くのかが分からなくなることです。

グローバル変数に依存したコードでは、

  • 関数の引数を見ても何が必要なのか分からない
  • 関数単体では処理内容を理解できない
  • 「実行してみないと挙動が分からない」状態になる

この状態が続くと、コードの理解・修正・拡張すべてに時間がかかるようになります。 つまり、バグ以前に「認知負荷」が一気に跳ね上がるんですね。

一方で、グローバル変数を減らし、

  • 必要な値は引数で受け取る
  • 結果は戻り値で返す
  • 状態を持つならクラスに閉じ込める

このようにデータの流れを明示的にするだけで、

  • バグの原因が追いやすくなる
  • 安心して修正できる
  • 「壊れにくいコード」になる

globalは「完全禁止」すべきものではありません。 ただし使っていいのは、

  • 書き換えない定数
  • 設定値などの参照専用データ

といった、役割が明確で限定できる場合だけです。

このあとからは、

  • そもそもPythonのグローバル変数とは何か
  • なぜ初心者ほど依存しやすいのか
  • どんな直し方が現実的なのか

を、順番に解きほぐしていきます。




Pythonにおけるグローバル変数の正体

まず前提として、Pythonの変数は「どこで定義されたか」によって 使える範囲(スコープ)が決まります。

グローバル変数とローカル変数の違い

Pythonでは、関数の外(ファイルのトップレベル)で定義された変数は グローバル変数になります。

一方、関数の中で定義された変数は、その関数の中でしか使えない ローカル変数です。

グローバル変数の特徴はとてもシンプルで、

  • どの関数からでも参照できる
  • どの関数からでも書き換えられる

という「自由さ」を持っています。

この自由さこそが、初心者にとっては魅力的に見えるポイントです。

「関数に引数を渡さなくても値が使える」 「戻り値を受け取らなくても状態を共有できる」

書く量が減って、パッと見はスッキリしますよね。

ただし、この便利さは規模が小さいうちだけの話です。 処理が増え、関数が増え、ファイルが増えてくると、

  • この変数はどこで使われている?
  • どこで書き換えられる可能性がある?
  • 今の値は本当に想定どおり?

といった疑問に、コードを追いかけないと答えられなくなります。

これはPythonが悪いわけではなく、 「設計を考えずに書けてしまう」というPythonの特性が原因です。

Pythonには便利な書き方がたくさんありますが、 その分、設計を意識しないと後から一気に破綻しやすい側面もあります。

この点については、次の記事で詳しく解説しています。

次のセクションでは、 なぜグローバル変数が「危険」と言われるのかを、 もう一段踏み込んで見ていきます。




なぜグローバル変数は危険と言われるのか

隠れた副作用がデバッグを極端に難しくする

グローバル変数の最大の問題は、 「この関数を呼ぶと、何が変わるのかが分からない」状態を作ってしまうことです。

本来、関数は

  • 引数を受け取って
  • 処理をして
  • 戻り値を返す

という流れだけを見れば、挙動が理解できるのが理想です。

ところが、関数の中でグローバル変数を書き換えていると、

  • 引数に書いていないのに状態が変わる
  • 戻り値がなくても結果に影響が出る

という隠れた影響が発生します。

これを副作用と呼びます。

副作用が増えると、

  • どの関数を呼んだせいで壊れたのか分からない
  • 処理の順番が変わるだけで挙動が変わる
  • printデバッグを入れても原因にたどり着けない

といった状態になりがちです。

この「副作用」という考え方をきちんと理解すると、 なぜグローバル変数が嫌われがちなのかが一気に腑に落ちます。


再利用性・テスト・拡張性が一気に下がる

グローバル変数に依存した関数は、 その変数が存在する前提でしか動きません。

つまり、

  • 別のファイルに移すと動かない
  • 別プロジェクトで再利用できない
  • 単体テストが書きづらい

という状態になります。

「この関数だけテストしたい」と思っても、 事前にグローバル変数を初期化しないといけなかったり、 テスト同士が互いに影響し合ったりします。

結果として、

  • テストを書かなくなる
  • 修正が怖くなる
  • 機能追加のたびに壊れる

という負のループに入りやすくなります。

この状態から抜け出すために行うのが、 リファクタリング(構造を整える修正)です。

「動くけど触りたくないコード」から 「安心して直せるコード」に変える考え方は、 以下の記事でも丁寧に解説しています。

次は、初心者がほぼ確実に一度は遭遇する UnboundLocalErrorについて見ていきましょう。




初心者が必ず一度は踏む「UnboundLocalError」

なぜこのエラーが起きるのか

グローバル変数を使っていると、初心者がほぼ確実に遭遇するのが UnboundLocalErrorです。

エラーメッセージは、だいたいこんな形で出ます。

UnboundLocalError: local variable 'x' referenced before assignment

意味が分かりづらくて、最初は戸惑いますよね。

このエラーの原因は、Pythonの変数の扱いルールにあります。

Pythonでは、関数の中で「代入」が行われた変数は、 その関数のローカル変数として扱われるという決まりがあります。

たとえば、関数の外に x というグローバル変数があったとしても、

  • 関数内で x = ...
  • 関数内で x += 1

のような代入があると、Pythonは 「これはローカル変数 x だ」と判断します。

その結果、

  • まだ値が代入されていない
  • でも参照しようとした

という矛盾が生まれ、UnboundLocalErrorが発生します。

これは仕様なので、初心者のミスというより グローバル変数依存そのものが原因と言えます。

このエラーを含め、初心者がよく出会うエラー全般については、 次の記事でまとめています。


globalキーワードは解決策なのか?

このエラーに出会ったとき、多くの人がたどり着くのが global キーワードです。

たしかに、関数内で

  • global x と宣言する

ことで、エラー自体は消えます。

ただし、これは根本的な解決ではありません

なぜなら、

  • 関数が外部状態にさらに強く依存する
  • どこで値が変わるか、より分かりにくくなる
  • バグの温床が増える

という状況を、むしろ悪化させてしまうからです。

UnboundLocalErrorは 「書き方が悪い」という警告ではなく、 「設計を見直したほうがいい」というサインだと考えると分かりやすいです。

次のセクションでは、 グローバル変数への依存を現実的に直していく方法を ステップごとに紹介していきます。




グローバル変数依存を直す3つの改善ステップ

ここからは、「じゃあどう直せばいいの?」という実践パートです。 いきなり完璧な設計を目指す必要はありません。 順番に直していくのがポイントです。

ステップ1:引数と戻り値でデータを渡す

まず最初にやるべきなのは、 グローバル変数に頼っている処理を、引数と戻り値に置き換えることです。

関数は本来、

  • 何を受け取って
  • 何を返すのか

が見ただけで分かる「部品」であるべきです。

グローバル変数を使っていると、

  • 引数に書いていない値に依存する
  • 戻り値がないのに状態が変わる

という、読み手にとって不親切な関数になります。

まずは、

  1. グローバル変数を使っている関数を洗い出す
  2. その変数を引数として受け取る形に変える
  3. 処理結果は return で返す

これだけでも、コードの見通しは一気に良くなります。

「動いているコードを直すのが怖い」と感じる人ほど、 構造だけを整えるリファクタリングの考え方を知っておくと安心です。

リファクタリング
✅ Amazonでチェックする✅ 楽天でチェックする


ステップ2:クラスで状態を閉じ込める

引数と戻り値だけでは管理しきれない場合は、 状態をクラスにまとめるのが次のステップです。

グローバル変数で状態を共有しているコードは、

  • 「誰がその状態を持っているのか」
  • 「誰が責任を持って変更するのか」

が曖昧になりがちです。

クラスを使うと、

  • 状態はインスタンス変数として管理される
  • 操作はメソッドに限定される

ため、グローバル空間を汚さずに済みます。

また、インスタンスを分ければ 複数の状態を同時に扱うことも簡単になります。

「クラス=難しいもの」と感じるかもしれませんが、 ここで使うのは最低限の考え方だけです。

設計の全体像を知りたい場合は、次の一冊が参考になります。

Pythonではじめるクリーンアーキテクチャ
✅ Amazonでチェックする✅ 楽天でチェックする


ステップ3:定数・設定値だけを安全に共有する

すべてのグローバル変数が悪いわけではありません。

以下のような値は、 「書き換えない前提」であればグローバルに置いても問題になりにくいです。

  • 定数(MAX_RETRY など)
  • 設定値(パス、URL、閾値など)

この場合のポイントは、

  • 実行中に変更しない
  • 役割を明確にする

ことです。

設定項目が増えてきたら、 config.py のような専用モジュールにまとめると、 コード全体の見通しが良くなります。

さらに一段進むと、 「設定値をどこから渡すか」という設計も重要になってきます。

次は、ここまで読んだ人が よく勘違いしやすいポイントを整理していきます。




よくある誤解・やりがちな失敗

ここまで読むと、「じゃあグローバル変数は全部ダメなの?」と感じるかもしれません。 でも、それは少し極端です。

「小規模スクリプトならOK」という言葉の誤解

よく「小さいスクリプトならグローバル変数を使っても問題ない」と言われます。

これは半分正しくて、半分間違いです。

正確には、

  • 行数が少ない
  • 一時的に使う
  • 将来ほぼ修正しない

こうした条件がそろっている場合に限り、 設計コストをかけない判断として許容される、という意味です。

逆に、

  • 少しずつ機能を足している
  • あとで直す前提で書いている
  • 自分以外が読む可能性がある

この時点で「小規模だから大丈夫」は通用しなくなります。


いきなり難しい設計に走ってしまう

グローバル変数の問題を知った直後に、

  • 急にクラスを増やす
  • 抽象化しすぎる
  • 設計本の真似をし始める

というのも、初心者がやりがちな失敗です。

最初から完璧な設計を目指す必要はありません。

大切なのは、

  • まず引数と戻り値で書けないか考える
  • それでも辛くなったらクラスを使う

という段階的な判断です。

「今の規模に対して、これはやりすぎ?」と立ち止まれる感覚が、 結果的に一番きれいなコードにつながります。


globalを書いた瞬間に罪悪感を持つ必要はない

globalキーワードを使ったからといって、 即ダメなコードになるわけではありません。

ただし、その行を書いた瞬間に、

  • 本当にここで共有すべき?
  • 引数で渡せない理由は?

と一度立ち止まれれば、それで十分です。




まとめ:グローバル変数依存から抜け出すと、コードは一気に楽になる

この記事では、Python初心者がやりがちな グローバル変数依存について見てきました。

ポイントを整理すると、次のとおりです。

  • 問題の本質は「グローバル変数そのもの」ではない
  • データの流れが見えなくなることで、バグと不安が増える
  • UnboundLocalErrorは設計を見直すサイン
  • まずは引数と戻り値でデータを明示する
  • 状態が増えたらクラスに閉じ込める
  • グローバルに置くのは定数・設定値だけに絞る

グローバル変数に頼ったコードは、 「書くのは楽だけど、読む・直すのがつらい」状態になりがちです。

一方で、データの流れを意識したコードは、

  • バグの原因がすぐ分かる
  • 修正に対する心理的ハードルが下がる
  • あとから機能を足しやすい

という、長く付き合える形になります。

最初から完璧な設計を目指す必要はありません。 でも、「なんとなくglobalを使う」段階を抜け出せると、 Pythonが一気に書きやすくなるはずです。

設計の考え方をもう一段深く知りたい人には、 次の一冊が良い補助線になります。

生成AI時代の新プログラミング実践ガイド
✅ Amazonでチェックする✅ 楽天でチェックする

「動くコード」から「壊れにくいコード」へ。 その第一歩として、次にglobalを書きたくなったとき、 ぜひ一度立ち止まってみてください 🙂


参考文献・参考リンク


よくある質問(Q&A)

Q
globalは絶対に使ってはいけませんか?
A

いいえ、絶対禁止というわけではありません。

グローバル変数は、

  • 定数として使う場合
  • 設定値など、実行中に書き換えない前提のデータ

であれば、問題になりにくいケースもあります。

ただし、「引数で渡すのが面倒だから」「とりあえず動くから」という理由で 安易に使い始めると、後から修正が大変になります。

globalを書く前に一度立ち止まれるかどうかが、 設計の分かれ目だと考えてください。

Q
スクリプトが100行程度でも設計を意識すべきですか?
A

はい、意識しておく価値は十分あります。

100行という数字自体よりも大切なのは、

  • 今後、機能を足す予定があるか
  • あとで自分が読み返す可能性があるか

です。

最初は小さくても、少しずつ処理を足していくスクリプトほど、 グローバル変数依存の影響が後から効いてきます。

完璧な設計は不要ですが、 引数と戻り値を意識するだけでも、 壊れにくさは大きく変わります。

Q
クラスと関数、どちらから学ぶべきですか?
A

最初は、関数と引数・戻り値をしっかり使えるようになるのがおすすめです。

多くのケースで、

  • グローバル変数を減らしたい
  • 処理の流れを分かりやすくしたい

という目的は、関数設計だけで十分に達成できます。

それでも、

  • 状態が増えて管理しきれない
  • 同じ処理を複数の状態で使いたい

と感じたタイミングが、クラスを学ぶベストな時期です。

「難しそうだから後回し」でも、「最初から全部クラス」でもなく、 必要になったときに使えるのが理想です。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク