1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonの変数スコープまとめ ─ グローバル・ローカル・global・nonlocal の使い分け

Last updated at Posted at 2025-09-07

はじめに

Python でコードを書くときにグローバル変数とローカル変数の扱いに迷う場面は少なくありません。

特に Java や C# のようなブロックごとにスコープが分かれる言語に慣れていると Python の挙動は直感と違って戸惑うことがあります。

この記事では学習課題でカレンダーを実装する過程で整理した内容をベースに、
Python の変数スコープを グローバル・ローカル・globalnonlocal に分けてまとめます。

グローバル変数に置くべきもの

絶対に書き換えない値(定数)

例:曜日リスト、バージョン番号、設定値など

python
WEEKDAYS = ["月", "火", "水", "木", "金", "土", "日"]
VERSION = "1.0.0"

→ 大文字で書くのが慣習(「定数ですよ」と伝えるため)。

複数の関数で共通して参照したい固定データ

例:曜日ヘッダを出力関数と計算関数で共通利用する場合。

ローカル変数にすべきもの

処理の途中で変わる値や一時的なデータ

例:日付計算の結果、ループカウンタ、ユーザー入力など。

python
def main():
    today = datetime.now()
    input_date = today.replace(day=1)

その関数にだけ関係するデータ

外から見えないほうが安全で関数の責務も明確になる。

原則ルール

  • 読み取り専用ならグローバルに置いてOK(定数扱い)。

  • 書き換える可能性があるなら関数内に閉じ込める。

迷ったときの判断ポイント

「他の関数から直接使いたい?」

→ YES → グローバル(ただし定数的なもののみ)
→ NO → ローカル

「将来テストや再利用時に勝手に変わると困る?」

→ 困る → ローカル
→ 困らない(固定データ) → グローバル

カレンダー課題での具体例

  • WEEK_HEADER(固定の曜日ヘッダ)
    → グローバル定数でOK

  • input_dateend_of_monthweeks_l
    → ローカル変数(毎月変わる値だから)

Pythonのスコープ挙動

1. グローバル変数とローカル変数の「かぶり」

Pythonでは関数内で代入をするとその名前は「ローカル変数」として扱われる。

そのため、モジュール直下(グローバル)で定義済みの変数があっても関数内で代入する処理があると「参照より前」にエラーが出るケースがある。

python
x = 10  # グローバル変数

def func():
    print(x)  # ←ここで参照したい
    x = 5     # ←代入があるため、xはローカル扱いになる

func()
# UnboundLocalError: cannot access local variable 'x' where it is not associated with a value

このように 「代入があるかどうか」でローカル扱いになるかが決まる ので注意が必要。

回避する方法2つ

  • グローバル変数を使うと明示する → global x(非推奨)

  • そもそも関数内で直接代入せず引数や戻り値でやり取りする(こちらが推奨)

2. Python は「関数スコープ」

if / for / while / try / except などのブロックごとにスコープは区切られず、関数単位でまとめて扱われる。

def sample():
    if True:
        x = 10
    print(x)  # OK → 10

3. 代入されないと未定義エラー

例外などで代入が飛んだ場合その後の参照でエラーになる。

python
def bad():
    try:
        z = int("abc")  # 例外発生
    except ValueError:
        pass
    print(z)  # NameError: z is not defined

4. Java / C# との違い

Java / C# は {} ごとにスコープが分かれるが Python は関数全体で共有される。
そのため ブロックをまたいで変数を共有できる

5. カレンダー課題で遭遇したケース

実際にカレンダー課題を実装する中で遭遇したのがこのようなケースです。

python
try:
    m = int(sys.argv[2])   # try 内で定義
except ValueError:
    sys.exit(1)

# try の外でも m を使える(関数スコープだから)
beginning_of_month = today.replace(month=m, day=1)

global キーワードについて

モジュール直下の変数を関数内で変更するときに使う。

便利だが副作用が大きくテストや再利用性を損なうため一般的に非推奨。

基本は 「定数を参照するだけ」 に留めるのが安全。

python
count = 0

def add():
    global count
    count += 1

→ 小規模スクリプトなら手軽だが、本格的なコードでは避けるのが無難。

nonlocal キーワードについて

ネストした関数の中から「一つ外側のスコープ」にある変数を変更したいときに使う。

主に クロージャで状態を持たせるとき に便利。

python
def outer():
    x = 0
    def inner():
        nonlocal x
        x += 1
        return x
    return inner

counter = outer()
print(counter())  # 1
print(counter())  # 2

使いどころはかなり限定的。

「クロージャを活用する特殊ケース」でしか見ないため無理に使う必要はない。

グローバルに置いてよい例外

定数(書き換えない値)

python
WEEK_HEADER = "月 火 水 木 金 土 日"

設定値(環境に依存する固定値)

例:デフォルトのファイルパスやAPIのエンドポイント。

グローバル変数を避けるべき理由

  • 可読性が下がる(どこで値が変わったか追いにくい)

  • テストしづらい(初期化しないと動かない)

  • バグの温床(複数の関数で書き換えると壊れる)

グローバルを避ける方法

  • 関数の引数・戻り値で受け渡す → 最もシンプルで安全。

  • 必要ならクラス化 → 状態をまとめて持たせたいときはインスタンス変数に。

まとめ

  • スクリプト的に書くとき → グローバルは定数だけ

  • 動的に変わる値は必ず関数ローカルに閉じ込める

  • 状態を持たせたいならクラスを使う

  • JavaやC#からPythonに来た人ほどスコープの違いに気をつけた方がいい

今回のカレンダー課題を通じて「定数はグローバル・処理結果はローカル」というシンプルな原則を意識することの大切さを再確認できた。

前回記事の紹介

この記事の前段として、コマンドライン引数 sys.argv を使ったカレンダー実装について整理しています。

興味のある方はこちらもどうぞ。(外部ブログ)
【Python】sys.argv とカレンダー課題で得た知見まとめ

クラス変数とインスタンス変数について

クラス変数とインスタンス変数の違いは Java などに慣れていると直感で理解しやすい部分ですが、Python 独自のポイントもあります。

このあたりは別の記事でまとめる予定です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?