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