- Python
UnboundLocalErrorの原因と直し方|Python
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期連続の黒字決算。