PythonのUnboundLocalErrorとは?原因と直し方を初心者向けに解説

ながみえ

Pythonで関数を使っていると、UnboundLocalErrorというエラーが表示されることがあります。

特に、関数の外で作った変数を関数の中で変更しようとしたときや、変数に値を入れる前に使ってしまったときに発生しやすいエラーです。

エラーメッセージに「local variable referenced before assignment」や「cannot access local variable」と表示されることもあり、初心者のうちは「変数は作ったはずなのに、なぜエラーになるの?」と迷いやすいポイントです。

この記事では、PythonのUnboundLocalErrorの意味、よくある原因、エラーになるコード例、修正方法、確認ポイントを初心者向けに解説します。

Pythonでよく出るエラーを一覧で確認したい方は、「Pythonエラー一覧」も参考にしてください↓↓

あわせて読みたい
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
あわせて読みたい
【完全無料】Python初心者向け完全ガイド
【完全無料】Python初心者向け完全ガイド

UnboundLocalErrorとは

UnboundLocalErrorは、関数の中でローカル変数を使おうとしたとき、その変数にまだ値が入っていない場合に発生するエラーです。

少し難しく感じるかもしれませんが、初心者のうちは「関数の中で使う変数の順番を間違えたときに出るエラー」と考えると分かりやすいです。

たとえば、次のように変数を表示してから値を入れようとすると、UnboundLocalErrorが発生します。

def show_message():
    print(message)
    message = "こんにちは"

show_message()

このコードでは、print(message) の時点で、まだ message に値が入っていません。

そのため、Pythonは「messageというローカル変数を使おうとしているけれど、まだ値が代入されていない」と判断し、UnboundLocalErrorを表示します。

ここで大切なのは、関数の中で変数に代入している場合、その変数は基本的に関数内だけで使うローカル変数として扱われるという点です。

ローカル変数やグローバル変数という言葉が出てくると難しく感じますが、まずは次のように整理しておくと理解しやすくなります。

用語意味
ローカル変数関数の中で作られ、基本的にその関数の中だけで使える変数
グローバル変数関数の外で作られ、プログラム全体から参照できる変数
代入前の参照変数に値を入れる前に、その変数を使ってしまうこと

UnboundLocalErrorは、特にローカル変数の扱いで発生しやすいエラーです。

変数名のスペルミスで起きるNameErrorとは違い、UnboundLocalErrorでは「変数名そのものが見つからない」というより、「ローカル変数として扱われているけれど、使う時点ではまだ値が入っていない」という状態になっています。

そのため、UnboundLocalErrorが出たときは、まずエラーメッセージに表示されている変数名を確認し、その変数が使われる前に値を代入しているかを見直すことが大切です。

UnboundLocalErrorが起きる主な原因

UnboundLocalErrorは、関数の中で変数を使う順番や、変数の扱い方を間違えたときに発生しやすいエラーです。

特に初心者のうちは、「関数の外で変数を作っているから使えるはず」と思って書いたコードで、UnboundLocalErrorになることがあります。

主な原因を整理すると、次のようになります。

原因内容確認すること
代入前に変数を使っている変数に値を入れる前に、print()などで使っている変数を使う前に代入しているか
関数外の変数を関数内で更新しているcount += 1 のように、関数内で同じ変数名を変更している関数内で同じ変数名に代入していないか
if文の中でだけ代入している条件によっては変数が作られないまま使われるどの条件でも変数に値が入るか
try文の中でだけ代入しているエラーが起きると、変数が作られないまま後続処理に進むexcept後でも変数が存在するか
内側の関数で外側の変数を変更している関数の中にある関数で、外側の変数を変更しようとしているnonlocalが必要なケースか

この中でも特に多いのが、関数外の変数を関数内で更新しようとするケースです。

たとえば、関数の外で count = 0 と書いている場合でも、関数の中で count += 1 と書くと、Pythonはその count を関数内のローカル変数として扱います。

count += 1 は一見すると「1を足しているだけ」に見えますが、実際には次のような処理をしています。

count = count + 1

つまり、右側の count を読み取ってから、左側の count に代入しています。

しかし、関数内のローカル変数としての count にまだ値が入っていない場合、読み取ることができません。その結果、UnboundLocalErrorが発生します。

また、if文やtry文の中だけで変数を作っている場合も注意が必要です。

条件によってその処理が実行されなかったり、途中でエラーが発生したりすると、変数が作られないまま次の処理に進んでしまうことがあります。

UnboundLocalErrorが出たときは、まず「その変数は、使われる前に必ず値が入るか」を確認しましょう。

すべてを暗記する必要はありません。エラーメッセージに表示されている変数名を手がかりにして、変数がどこで作られ、どこで使われているかを順番に見ていくことが大切です。

UnboundLocalErrorのエラー例と修正例

ここからは、実際にUnboundLocalErrorが発生するコードと、その修正例を見ていきます。

UnboundLocalErrorは、原因だけを文章で読むよりも、コード例で確認したほうが理解しやすいエラーです。まずは短いコードで、「どこで変数を使っていて、どこで代入しているか」に注目してみましょう。

関数内で変数を代入前に使っている例

まずは、関数の中で変数を使う順番を間違えている例です。

次のコードでは、message に値を入れる前に print(message) で表示しようとしています。

def show_message():
    print(message)
    message = "こんにちは"

show_message()

このコードを実行すると、UnboundLocalErrorが発生します。

関数の中に message = "こんにちは" という代入があるため、Pythonは message をこの関数内のローカル変数として扱います。

しかし、実際には print(message) の時点で、まだ message に値が入っていません。そのため、「ローカル変数messageを使おうとしたけれど、まだ値がない」と判断されます。

修正するには、変数を使う前に値を代入します。

def show_message():
    message = "こんにちは"
    print(message)

show_message()

このように、message に値を入れてから print(message) を実行すれば、UnboundLocalErrorは発生しません。

変数を使うときは、「その前の行までに値が入っているか」を確認することが大切です。

関数外の変数を関数内で更新しようとする例

次は、初心者が特につまずきやすい例です。

関数の外で作った変数を、関数の中で更新しようとすると、UnboundLocalErrorが発生することがあります。

count = 0

def add_count():
    count += 1
    print(count)

add_count()

このコードでは、関数の外で count = 0 と書いています。

そのため、一見すると関数内でも count を使えそうに見えます。しかし、関数内で count += 1 と書いているため、Pythonは count を関数内のローカル変数として扱います。

count += 1 は、次の処理とほぼ同じ意味です。

count = count + 1

右側の count を読み取ってから、1を足して、左側の count に代入しています。

しかし、関数内のローカル変数としての count には、まだ値が入っていません。そのため、UnboundLocalErrorになります。

この場合は、引数と戻り値を使って書くと分かりやすくなります。

count = 0

def add_count(count):
    count += 1
    return count

count = add_count(count)
print(count)

このコードでは、関数の外にある count を引数として関数に渡し、関数の中で1を足した結果を return で返しています。

初心者のうちは、関数の外の変数を直接変更しようとするより、引数と戻り値を使って値を受け渡しする書き方がおすすめです。

なお、global を使って修正する方法もあります。

count = 0

def add_count():
    global count
    count += 1
    print(count)

add_count()

global count と書くと、関数の外にある count を関数内で変更できるようになります。

ただし、global を多く使うと、どこで変数の値が変わったのか分かりにくくなることがあります。そのため、まずは引数と戻り値で書けないかを考えるとよいでしょう。

if文の中でだけ変数を代入している例

UnboundLocalErrorは、if文の条件によって変数が作られない場合にも発生します。

次のコードでは、点数が80点以上なら result に「合格」を代入し、そのあとで result を表示しています。

def check_score(score):
    if score >= 80:
        result = "合格"

    print(result)

check_score(60)

このコードでは、check_score(60) としているため、score >= 80 の条件は成り立ちません。

その結果、if文の中にある result = "合格" は実行されません。つまり、result に値が入らないまま print(result) が実行されます。

このように、条件によって変数が作られない可能性がある場合、UnboundLocalErrorが発生します。

修正するには、if文の前で初期値を入れておきます。

def check_score(score):
    result = "不合格"

    if score >= 80:
        result = "合格"

    print(result)

check_score(60)

このコードでは、最初に result = "不合格" と代入しています。

そのため、if文の条件が成り立たなかった場合でも、result には値が入っています。どの条件でも変数に値が入るようにしておくことで、UnboundLocalErrorを防ぐことができます。

try文の中でだけ変数を作っている例

try文の中だけで変数を作っている場合も注意が必要です。

次のコードでは、文字列を数値に変換して、その結果を表示しようとしています。

def convert_number(text):
    try:
        number = int(text)
    except ValueError:
        print("数値に変換できません")

    print(number)

convert_number("abc")

このコードでは、int(text) で文字列を整数に変換しようとしています。

しかし、convert_number("abc") としているため、"abc" は整数に変換できません。その結果、number = int(text) は成功せず、except ValueError の処理に進みます。

この時点では、number という変数に値が入っていません。

そのあとで print(number) を実行しようとしているため、UnboundLocalErrorが発生します。

修正するには、変換に成功した場合だけ number を表示するようにします。

def convert_number(text):
    try:
        number = int(text)
        print(number)
    except ValueError:
        print("数値に変換できません")

convert_number("abc")

このコードでは、number = int(text) が成功した場合だけ、すぐ下の print(number) が実行されます。

もし数値に変換できない場合は、exceptの中のメッセージだけが表示されます。変数が作られない可能性がある処理では、その変数をどこで使うかにも注意しましょう。

内側の関数で外側の変数を変更している例

少し発展的な例ですが、関数の中にさらに関数を書く場合にも、UnboundLocalErrorが発生することがあります。

次のコードでは、外側の関数 outer() の中で count を作り、内側の関数 inner() でその値を増やそうとしています。

def outer():
    count = 0

    def inner():
        count += 1
        print(count)

    inner()

outer()

このコードでは、inner() の中で count += 1 と書いています。

そのため、Pythonは inner() の中の count をローカル変数として扱います。しかし、inner() の中では count に値を入れる前に count += 1 で読み取ろうとしているため、UnboundLocalErrorになります。

外側の関数にある変数を、内側の関数で変更したい場合は、nonlocal を使います。

def outer():
    count = 0

    def inner():
        nonlocal count
        count += 1
        print(count)

    inner()

outer()

nonlocal count と書くことで、inner() の中の count は、外側の関数 outer() にある count を指すようになります。

ただし、nonlocal は少し発展的な書き方です。初心者のうちは、「関数の中にさらに関数を書く場合は、変数の扱いが少し複雑になる」と覚えておくだけでも十分です。

UnboundLocalErrorが出たときは、変数名だけを見るのではなく、「その変数がどの関数の中で作られているか」「どのタイミングで値が入っているか」を確認しましょう。

UnboundLocalErrorが出たときの確認ポイント

UnboundLocalErrorが出たときは、エラーメッセージに表示されている変数名を手がかりにして、変数の使われ方を順番に確認しましょう。

いきなりコード全体を見直そうとすると大変ですが、「どの変数が原因か」「その変数にいつ値が入るか」を見ると、原因を見つけやすくなります。

確認するポイントは、次のとおりです。

  1. エラーメッセージに表示されている変数名を確認する
  2. その変数を使う前に、値を代入しているか確認する
  3. 関数内で同じ変数名に代入していないか確認する
  4. +=-=*= などで変数を更新していないか確認する
  5. if文の条件によって、変数が作られない場合がないか確認する
  6. try文の中だけで変数を作っていないか確認する
  7. 関数外の変数を変更したい場合、引数と戻り値で書けないか考える
  8. どうしても必要な場合だけ、globalnonlocal を検討する

特に重要なのは、変数を使う前に必ず値が入っているかを確認することです。

たとえば、次のようなコードでは、result が作られないまま使われる可能性があります。

def check_score(score):
    if score >= 80:
        result = "合格"

    print(result)

この場合、score が80未満だと、if文の中が実行されません。そのため、result に値が入らないまま print(result) が実行されます。

このようなときは、if文の前に初期値を入れておくと安心です。

def check_score(score):
    result = "不合格"

    if score >= 80:
        result = "合格"

    print(result)

また、関数の外で作った変数を、関数の中で変更しようとしていないかも確認しましょう。

次のように count += 1 と書いている場合、Pythonは count を関数内のローカル変数として扱います。

count = 0

def add_count():
    count += 1
    print(count)

このようなコードでUnboundLocalErrorが出た場合は、まず引数と戻り値を使って書けないか考えるとよいです。

count = 0

def add_count(count):
    count += 1
    return count

count = add_count(count)
print(count)

global を使えば直せる場合もありますが、初心者のうちは使いすぎに注意しましょう。

global を多く使うと、変数の値がどこで変わったのか分かりにくくなります。まずは、関数に値を渡して、処理した結果を返す書き方を意識すると、コードの流れを理解しやすくなります。

UnboundLocalErrorは、エラー名だけを見ると難しく感じるかもしれません。しかし、確認することはそれほど多くありません。

まずは、エラーに表示された変数名を探し、その変数が「使われる前に代入されているか」「関数内でローカル変数として扱われていないか」を順番に確認しましょう。

UnboundLocalErrorに関するよくある質問

ここでは、UnboundLocalErrorについて初心者が疑問に感じやすいポイントをまとめます。

エラーの意味だけでなく、なぜ変数を定義しているのにエラーになるのか、global を使ってよいのかなども確認しておきましょう。

UnboundLocalError: local variable referenced before assignment とはどういう意味ですか?

「ローカル変数を、値を入れる前に使っています」という意味です。

Pythonでは、関数の中で変数に代入している場合、その変数は基本的にローカル変数として扱われます。

そのため、次のように値を入れる前に変数を使うと、UnboundLocalErrorが発生します。

def show_name():
    print(name)
    name = "太郎"

show_name()

このコードでは、print(name) の時点で、まだ name に値が入っていません。

修正するには、変数を使う前に代入します。

def show_name():
    name = "太郎"
    print(name)

show_name()

まずは、エラーメッセージに表示されている変数名を探し、その変数が使われる前に値を代入しているか確認しましょう。

変数を関数の外で定義しているのにUnboundLocalErrorが出るのはなぜですか?

関数の中で同じ名前の変数に代入しているためです。

関数の外で変数を作っていても、関数の中で同じ変数名に代入すると、Pythonはその名前を関数内のローカル変数として扱います。

たとえば、次のコードを見てみましょう。

count = 0

def add_count():
    count += 1
    print(count)

add_count()

関数の外に count = 0 がありますが、関数の中で count += 1 と書いています。

この場合、Pythonは add_count() の中の count をローカル変数として扱います。しかし、ローカル変数としての count にはまだ値が入っていないため、UnboundLocalErrorになります。

このような場合は、引数と戻り値を使うと分かりやすくなります。

count = 0

def add_count(count):
    count += 1
    return count

count = add_count(count)
print(count)

関数の外の変数を直接変更しようとするより、関数に値を渡して、処理した結果を受け取る形にすると、コードの流れを理解しやすくなります。

globalを使えばUnboundLocalErrorは直りますか?

global を使うことで直せる場合もあります。

global は、関数の外にあるグローバル変数を、関数の中で変更したいときに使います。

count = 0

def add_count():
    global count
    count += 1
    print(count)

add_count()

このコードでは、global count と書いているため、関数の中の count は関数外の count を指します。

ただし、初心者のうちは global に頼りすぎないほうがよいです。

global を多く使うと、変数の値がどこで変わったのか分かりにくくなります。まずは、引数と戻り値を使って書けないかを考えるとよいでしょう。

UnboundLocalErrorとNameErrorの違いは何ですか?

NameErrorは、Pythonが指定された名前を見つけられないときに発生するエラーです。

一方、UnboundLocalErrorは、関数内でローカル変数として扱われている名前を、値が入る前に使ったときに発生します。

たとえば、次のコードはNameErrorになります。

print(message)

このコードでは、message という変数がどこにも定義されていません。

一方、次のコードはUnboundLocalErrorになります。

def show_message():
    print(message)
    message = "こんにちは"

show_message()

このコードでは、関数内に message = "こんにちは" という代入があります。そのため、Pythonは message をローカル変数として扱います。

しかし、print(message) の時点ではまだ値が入っていないため、UnboundLocalErrorになります。

簡単にいうと、NameErrorは「その名前が見つからない」、UnboundLocalErrorは「ローカル変数として扱われているが、まだ値が入っていない」と考えると分かりやすいです。

nonlocalはどのようなときに使いますか?

nonlocal は、関数の中にさらに関数があり、内側の関数から外側の関数の変数を変更したいときに使います。

少し発展的な内容ですが、次のようなコードではUnboundLocalErrorが発生します。

def outer():
    count = 0

    def inner():
        count += 1
        print(count)

    inner()

outer()

inner() の中で count += 1 と書いているため、Pythonは countinner() のローカル変数として扱います。

しかし、inner() の中ではまだ count に値が入っていないため、UnboundLocalErrorになります。

この場合は、nonlocal を使って、外側の関数にある変数を使うことを明示します。

def outer():
    count = 0

    def inner():
        nonlocal count
        count += 1
        print(count)

    inner()

outer()

nonlocal count と書くことで、inner() の中の count は、外側の関数 outer() にある count を指します。

ただし、nonlocal は関数の中にさらに関数を書く場合に使うものです。通常の関数では、まず引数と戻り値で値を受け渡しできないかを考えるとよいでしょう。

まとめ|UnboundLocalErrorは変数を使う順番を確認しよう

UnboundLocalErrorは、Pythonでローカル変数を代入前に使ったときに発生するエラーです。

特に、関数の外で作った変数を関数内で更新しようとした場合や、if文・try文の条件によって変数が作られない場合によく起きます。

エラーが出たときは、まずエラーメッセージに表示されている変数名を確認しましょう。そのうえで、その変数が使われる前に値を代入しているか、関数内でローカル変数として扱われていないかを順番に見直すことが大切です。

globalnonlocal を使えば直せる場合もありますが、初心者のうちは、まず引数と戻り値を使って値を受け渡しできないか考えるとよいでしょう。

Pythonでよく出るエラーをまとめて確認したい方は、「Pythonエラー一覧」も参考にしてください。

あわせて読みたい
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
あわせて読みたい
【完全無料】Python初心者向け完全ガイド
【完全無料】Python初心者向け完全ガイド
記事URLをコピーしました