UnboundLocalError: cannot access local variable 'count' where it is not associated with a value は、関数の中の変数(ローカル変数)を、値を入れる前に読んだときのエラーです。 Python 3.10 以前では、同じエラーが local variable 'count' referenced before assignment と表示されます。

原因は大きく2つです。

原因 典型 直し方
関数の外の変数を、関数の中で書き換えようとした count += 1(count は関数の外で定義) global count(入れ子の関数なら nonlocal)、または引数と戻り値で受け渡す
値を入れる処理が、実行されなかった if・for・try の中でだけ代入している 先に初期値を入れる、または値が無いときの処理を書く

確認環境:Python 3.10・3.11・3.12・3.13、ruff 0.17.0、pylint 4.1.2(確認日 2026年10月11日)。以下の6パターンを、4つの版すべてで再現しました。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「UnboundLocalErrorの原因と直し方|Python」

メッセージは版で違う(意味は同じ)

Python の版 メッセージ
3.10 以前 UnboundLocalError: local variable 'count' referenced before assignment
3.11 以降 UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

なぜ起きるのか:関数の中で代入した名前は、関数全体でローカル変数になる

count = 0              # 関数の外(グローバル変数)

def inc():
    count += 1         # ← ここでエラー
    return count

count += 1 は「count を読んで、1足して、count に入れる」処理です。関数の中のどこかで count に代入があると、Python はその関数の中の count をすべて「関数の中の変数」として扱います(Python 公式の FAQ)。関数の中の count にはまだ値が無いので、最初の読み取りでエラーになります。外の count = 0 は使われません。

同じ名前の変数が関数の外にあっても関係ありません。 「値はあるのに、なぜ」と感じるのはこのためです。

再現:6つのパターン

# パターン エラーになった変数
1 外の変数に += count
2 for の中でだけ代入し、空のリストを渡した result
3 try の中で代入し、例外で飛ばされた data
4 関数の後半で同じ名前に代入している(前半で読む) name
5 入れ子の関数で、外側の関数の変数に += n
6 except ... as e と同じ名前の変数を、except の後で読んだ e

1. 外の変数に += → global

count = 0
def inc():
    global count       # 外の count を使うと宣言する
    count += 1
    return count

print(inc(), inc())    # 1 2

ただし、global で外の変数を書き換える書き方は、どこで値が変わったか追いにくくなります。可能なら、引数で受け取って戻り値で返す形にします。

def inc(count: int) -> int:
    return count + 1

count = inc(count)

2. for・if の中でだけ代入 → 初期値を入れる

def total(items):
    for x in items:
        result = x * 2       # items が空だと、一度も実行されない
    return result

total([])   # UnboundLocalError: cannot access local variable 'result' ...

データが0件のときだけ落ちるので、テストで見つかりにくいパターンです。ループの前に初期値を入れます。

def total(items):
    result = 0
    for x in items:
        result += x * 2
    return result

print(total([]), total([1, 2]))   # 0 6

3. try の中で代入、例外で飛ばされた

def fetch(ok):
    try:
        if not ok:
            raise ValueError("失敗")
        data = {"id": 1}
    except ValueError as e:
        print("エラー:", e)
    return data              # 例外のときは data に何も入っていない
エラー: 失敗
fetch: UnboundLocalError: cannot access local variable 'data' where it is not associated with a value

例外を print して握りつぶしたあとで、続きの処理が値を使うと起きます。例外のときに何を返すかを決めて書きます。

def fetch(ok):
    try:
        if not ok:
            raise ValueError("失敗")
        return {"id": 1}
    except ValueError as e:
        print("エラー:", e)
        return None          # 呼び出し側で None を判定する

4. 関数の後半で同じ名前に代入している

name = "佐藤"
def shadow():
    print(name)          # ← ここでエラー
    name = "鈴木"         # 後ろの行の代入で、name がローカル変数になる

デバッグ用に print を足した、変数名を使い回した、などで起きます。後ろの行に、同じ名前への代入(=、for name in、import name など)がないかを探します。

5. 入れ子の関数 → nonlocal

def outer():
    n = 0
    def inner():
        nonlocal n          # 外側の関数の n を使う
        n += 1
        return n
    return inner()

print(outer())   # 1

nonlocal は、外側の関数の変数に使います。モジュールの一番外の変数は global です。

6. except ... as e の変数は、except の後で消える

def del_after():
    e = "x"                    # 先に e に値を入れていても
    try:
        raise KeyError("k")
    except KeyError as e:      # 同じ名前 e を使うと
        pass
    return e                   # ← UnboundLocalError

except ... as 名前 の変数は、except を抜けるときに削除されます(Python の言語リファレンスに、del されるのと同じと書かれています)。同じ名前の変数を前から使っていると、それも消えます。例外の変数には、別の名前(err など)を使います。

    except KeyError as err:    # 別の名前にする
        pass
    return e                   # "x"

NameError との違い

エラー 意味
UnboundLocalError 関数の中の変数として認識されているが、値が入っていない
NameError: name 'x' is not defined その名前が、どこにも定義されていない(打ち間違いなど)

UnboundLocalError は NameError の一種です。except NameError でも捕まえられますが、捕まえるより原因の書き方を直します。

実行する前に見つける:ruff と pylint

パターン ruff 0.17.0(F823) pylint 4.1.2(E0601)
1. 外の変数に += 見つかる 見つからない
2. for の中でだけ代入 見つからない 見つからない
3. try の中で代入 見つからない 見つからない
4. 後半で同じ名前に代入 見つかる 見つかる
5. 入れ子の関数で += 見つかる 見つからない
6. except as で消える 見つからない(「使われていない変数」の警告のみ) 見つからない
$ ruff check --select F823 u.py
u.py:4:5: F823 Local variable `count` referenced before assignment
u.py:21:11: F823 Local variable `name` referenced before assignment
u.py:28:9: F823 Local variable `n` referenced before assignment

「外の変数を書き換える」系(1・4・5)は ruff で事前に見つかりました。 一方、「実行の流れによって代入されない」系(2・3)は、どちらのツールでも見つかりませんでした。0件・例外のときのテストを書いて確かめます。

確認の手順(チェックリスト)

順番 確認すること 方法
1 どの変数か メッセージの '変数名'
2 関数の外にも同じ名前があるか あれば、関数の中のどこかで代入していないか探す
3 +=・-= を使っていないか global・nonlocal、または引数と戻り値に
4 if・for・try の中でだけ代入していないか 前に初期値を入れる。0件・例外のときを確かめる
5 except ... as と同じ名前を使っていないか 例外の変数名を変える
6 再発を防ぐ ruff の F823、0件・例外のテスト

よくある質問

Q. グローバル変数を読むだけならエラーになりませんか。 A. なりません。関数の中で代入しなければ、外の変数をそのまま読めます。代入(=・+= など)があるときだけ、関数の中の変数として扱われます。

Q. リストに append するだけでも global が要りますか。 A. 要りません。items.append(x) はリストの中身を変えるだけで、items という名前への代入ではないためです。items = items + [x] や items += [x] のように、名前に代入するときに起きます。

まとめ

  • 関数の中で代入した名前は、関数全体でローカル変数になる。外に同じ名前があっても使われない
  • 外の変数に += → global(入れ子なら nonlocal)。できれば引数と戻り値で受け渡す
  • if・for・try の中でだけ代入 → 先に初期値。0件・例外のときだけ落ちる
  • except ... as e の変数は except を抜けると消える。同じ名前を使わない
  • 3.10 以前は referenced before assignment、3.11 以降は cannot access local variable
  • ruff の F823 で一部は事前に見つかる。実行の流れによるものはテストで確かめる

参考・出典

確認日はいずれも 2026年10月11日です。

  • Python ドキュメント「Programming FAQ」(Why am I getting an UnboundLocalError when the variable has a value?):https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
  • Python 言語リファレンス「Compound statements」(The try statement):https://docs.python.org/3/reference/compound_stmts.html#the-try-statement

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「UnboundLocalErrorの原因と直し方|Python」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?