Code Fix

中級

代入より前に参照したUnboundLocalErrorの原因

関数内で変数に代入すると、Pythonはその変数を自動的にローカル変数とみなします。代入より前に参照すると発生します。

エラーメッセージの読み方

Traceback (most recent call last):
main.py
ファイル名
5
行番号 — 実際にクラッシュした行
increment
発生場所 — <module> ならトップレベル、関数名ならその関数の中
UnboundLocalError
例外クラス — 何が起きたか。ここを検索するのが最短です
cannot access local variable 'count' where it is not associated with a value
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  count = 0
 2  
 3  def increment():
 4                    
               ^
 5      count = count + 1
 6      return count
 7  
 8  print(increment())
Traceback (most recent call last): File "main.py", line 8, in <module> print(increment()) ^^^^^^^^^^^ File "main.py", line 5, in increment count = count + 1 ^^^^^ UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

関数内で変数に代入すると、Pythonはその変数を自動的にローカル変数とみなします。グローバル変数を書き換えたい場合はglobal宣言が必要です。

直し方: (空) を global count にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  total = 100
 2  
 3  def add_tax():
 4                    
               ^
 5      total = total * 1.1
 6      return total
 7  
 8  print(add_tax())
Traceback (most recent call last): File "main.py", line 8, in <module> print(add_tax()) ^^^^^^^^^ File "main.py", line 5, in add_tax total = total * 1.1 ^^^^^ UnboundLocalError: cannot access local variable 'total' where it is not associated with a value

代入している行が後にあっても、Pythonは関数全体を先読みしてtotalをローカル変数と判断します。読み込む行が先に実行されるため、その時点でまだ値がありません。

直し方: (空) を global total にします。

この問題を解いてみる →

パターン3

 1  flag = False
 2  
 3  def toggle():
 4                   
              ^
 5      flag = not flag
 6      return flag
 7  
 8  print(toggle())
Traceback (most recent call last): File "main.py", line 8, in <module> print(toggle()) ^^^^^^^^ File "main.py", line 5, in toggle flag = not flag ^^^^ UnboundLocalError: cannot access local variable 'flag' where it is not associated with a value

真偽値の反転のような単純な処理でも同じです。関数の外の変数を書き換えるにはglobal宣言が必要です。

直し方: (空) を global flag にします。

この問題を解いてみる →

パターン4

 1  items = []
 2  
 3  def add_item(x):
 4                    
               ^
 5      items = items + [x]
 6      return items
 7  
 8  print(add_item(5))
Traceback (most recent call last): File "main.py", line 8, in <module> print(add_item(5)) ^^^^^^^^^^^ File "main.py", line 5, in add_item items = items + [x] ^^^^^ UnboundLocalError: cannot access local variable 'items' where it is not associated with a value

リストであっても規則は同じです。関数内で代入している時点でローカル変数扱いになります。

直し方: (空) を global items にします。

この問題を解いてみる →

パターン5

 1  score = 0
 2  
 3  def add_point():
 4                    
               ^
 5      score = score + 1
 6      return score
 7  
 8  print(add_point())
Traceback (most recent call last): File "main.py", line 8, in <module> print(add_point()) ^^^^^^^^^^^ File "main.py", line 5, in add_point score = score + 1 ^^^^^ UnboundLocalError: cannot access local variable 'score' where it is not associated with a value

得点を1つ増やすだけの単純な処理でも、global宣言を忘れると発生します。

直し方: (空) を global score にします。

この問題を解いてみる →

よくある誤解

関数の外で同名の変数が定義されていても、関数内で一度でも代入している変数はローカル扱いになります。読み込む前に代入されているかどうかは関係なく、関数全体を見て判断されます。

実務での勘所

この判定は実行時に1行ずつ決まるのではなく、CPythonがその関数のコードを実行する前に、関数の中に代入文がある変数をあらかじめ「ローカル変数」としてリストアップしておくという、コンパイル段階に近い仕組みで行われます。そのため、代入文が実際に実行される前の行でその変数を参照すると、外側のスコープを探しに行くことなく「ローカル変数として登録されているのに値がまだ無い」というUnboundLocalErrorになります。外側の変数を明示的に使いたい場合は、globalまたはnonlocalという宣言でこの自動判定を上書きする必要があります。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)