プログラミング

PythonのNameErrorを直す方法 変数名と定義する順番を確認

NameErrorの原因を、つづり・実行順・if文の分岐・関数のスコープから切り分けます。returnを使う修正例と練習問題の解答付き。

「変数はちゃんと書いてあるのに!」。NameErrorが出たときは、コードに名前があるかだけでなく、エラーの行へ来た時点で、その名前を使えるかを確認します。

見る順番は、名前のつづり、値を用意する順番、使える範囲です。Python 3の短い例を動かしながら、違いを整理しましょう。各コード欄は、それぞれ別の例として実行してください。

エラー文のどの部分を読む?

score = 80
print(socre)

この例では、次のようなエラーになります。補助的な候補表示はPythonのバージョンなどで変わります。

NameError: name 'socre' is not defined

注目するのは'socre'です。Pythonは、その場所から使える名前を探しましたが、見つけられませんでした。NameErrorの公式説明

上の行で作った名前はscore。最後の行だけcとoが入れ替わっています。次なら80を表示できます。

score = 80
print(score)

長いエラー表示は、まず最後のエラー名と名前、その上のファイル名・行番号を見ます。いきなり全文を理解しなくても、修正する場所を絞れます。例外表示の読み方

1. 大文字・小文字と引用符を確かめる

scoreとScoreは別の名前です。目で似ていると判断せず、代入する行と使う行の表記を比べてください。

また、表示したい文章を引用符で囲んでいない場合にも起こります。

print(hello)

これは、helloという名前の値を表示するコードです。文字そのものを表示したいなら、次のように文字列にします。

print("hello")

すべてに引用符を付ければよいわけではありません。print("score")は80ではなく、文字列のscoreを表示します。「値を取り出したいのか、文字をそのまま表示したいのか」を分けましょう。

2. 名前を用意する行が先に実行されている?

次は、つづりが合っていても失敗する例です。

print(total)
total = 300

ファイルを上から実行すると、1行目ではまだtotalへ値を代入していません。直すなら順番を入れ替えます。

total = 300
print(total)

関数も同様です。通常のスクリプトでは、def greet():が実行されて名前が用意されたあとに呼び出します。

def greet():
    print("こんにちは")

greet()

関数の中に書いた処理は、defの位置へ来ただけでは実行されません。ここでは関数を用意し、最後のgreet()で中身を動かしています。Python公式の関数の定義

if文の中を通っていない場合もある

score = 50

if score >= 60:
    message = "合格です"

print(message)

50は条件を満たさないため、messageを作る行を通りません。この場合は、必要な両方の分岐で値を決めます。

score = 50

if score >= 60:
    message = "合格です"
else:
    message = "もう一度復習しましょう"

print(message)

ifの外に使う値があるなら、「どの道を通っても用意されるか」まで確認すると原因が見えます。

3. 関数の中の変数を外から使っていない?

def make_message():
    message = "準備できました"

make_message()
print(message)

関数を呼んでも、最後の行でNameErrorになります。関数内で作ったmessageは、その関数の中で使うローカル変数だからです。名前を使える範囲をスコープと呼びます。名前の検索とスコープの公式説明

外でも必要なら、returnで値を返して受け取ります。

def make_message():
    message = "準備できました"
    return message

text = make_message()
print(text)

表示は「準備できました」です。関数内のmessageという変数を外へ移動させたのではなく、返された値をtextという別の名前で受け取っています。

globalで全部を外から使えるようにする前に、入力を引数で渡し、結果をreturnで返す形を考えると、値の流れが追いやすくなります。関数と戻り値の入門にもつながる内容です。

import忘れとUnboundLocalErrorも見分ける

math.sqrt(16)を使うなら、先にimport mathが必要です。

import math

print(math.sqrt(16))

これなら4.0を表示します。mathを読み込まずに使うのはNameError、importしたいモジュール自体が見つからないのはModuleNotFoundErrorです。

一方、関数内で代入する変数を、その代入より先に読み取るとUnboundLocalErrorになる場合があります。

count = 10

def add_one():
    count = count + 1

add_one()

関数内にcountへの代入があるため、ここではローカル変数として扱われます。右側のcountには、まだ値がありません。外の10を使いたい意図なら、引数で受け取り、増やした値を返せます。

def add_one(count):
    return count + 1

count = add_one(10)
print(count)

この違いが分かれば、エラーをまとめてexcept NameErrorで隠さず、名前を用意する位置を直せます。

練習:計算結果を関数の外で表示する

次は最後の行で失敗します。450を関数の外で表示できるように直してください。

def calculate_total():
    total = 150 * 3

calculate_total()
print(total)

模範解答

def calculate_total():
    total = 150 * 3
    return total

result = calculate_total()
print(result)

解説

totalは関数内の名前です。return totalで450を返し、呼び出す側のresultで受け取ると表示できます。名前は違っても、受け渡す値は450です。

NameErrorを見たら、エラーに出た名前から、つづり・実行順・スコープをたどってみてください。変数の代入がまだ曖昧なら、変数と入力の基本から確認できます。

← 記事一覧へ戻る