{ }codelper

学ぶ › Python

さらに先へ · 22

よくある間違いとエラーメッセージ

エラーメッセージの読み方と、どの言語でも出る間違い:1 つずれ、= と ==、整数の割り算、null、範囲外の添字。

どの言語でも出る間違いがあります。
エラーメッセージの読み方と一緒に覚えましょう。
下の例は、添字が範囲内か、割る数が 0 でないかを先に確かめてから使います。

def get(a, i):    if 0 <= i < len(a):          # a[-1]도 막아요(Python에서는 마지막 값)        return a[i]    return None  def safe_div(x, y):    if y == 0:        return None    return x // y  n = int(input())a = list(map(int, input().split()))input()for i in map(int, input().split()):    v = get(a, i)    if v is None:                # if not v: 로 쓰면 0도 걸려요        print(f"a[{i}]: out of range")    else:        print(f"a[{i}] = {v}")x, y = map(int, input().split())q = safe_div(x, y)print(f"{x} / {y}: cannot divide" if q is None else f"{x} / {y} = {q}")print(f"average {sum(a) / n:.1f}")
stdin
5
3 1 4 1 5
3
2 7 -1
7 0
stdout
a[2] = 4
a[7]: out of range
a[-1]: out of range
7 / 0: cannot divide
average 2.8

ポイント

  • エラーメッセージではエラー名・理由・行番号を探します。
    Python は一番下の行から読みます。
  • コンパイルする言語(C・C++・Java・C#)では、エラーがいくつ出ても最初のエラーから直します。
    後ろのものは最初のエラーにつられて出ていることが多いからです。
  • 添字は 0 から n - 1 までなので、ループは i < n です。
    i <= n と書くと 1 つはみ出す 1 つずれ(off-by-one)になります。
  • = は代入、== は比較です。
  • 割る前に 0 でないか、使う前に空の値(null)でないかを先に確かめます。
  • 変数は作るときに初期値を与えます(int sum = 0;)。

言語ごとの書き方

Python最後の行に IndexError: list index out of range のような名前と理由、その上に行番号。
0 で割ると ZeroDivisionError、None で計算すると TypeError、ない名前は NameError。
a[-1] はエラーではなく最後の値で、if not v: は 0 も引っかけます(v is None で確かめます)
JavaScript範囲外の添字はエラーなしで undefined、7 / 0 は Infinity。
空の値は null と undefined で、undefined + 1 は NaN、null + 1 は 1 になって黙って間違えます。
比較は ===("1" == 1 は真)
TypeScriptJavaScript と同じです
Java1 行目が ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 5、下の at Main.main(Main.java:12) が行番号。
0 で割ると ArithmeticException、null は NullPointerException(int には入らないので Integer)。
初期値がないと "might not have been initialized" のコンパイルエラー
C#範囲外は IndexOutOfRangeException、0 で割ると DivideByZeroException。
空の値は int?。
初期値がないとコンパイルエラー CS0165
C++a[i] は検査しないので範囲外は未定義動作、a.at(i) は std::out_of_range 例外。
整数の 0 での割り算も未定義動作(たいてい落ちます)。
空の値は std::optional。
int sum; はごみの値から始まります
C配列の範囲検査がないので未定義動作:でたらめな値、別の変数の書き換え、落ちる。
0 での割り算と初期化していないローカル変数は C++ と同じです
Craykon範囲外は「リストには 0〜4 番しかありません」で止まります。
7 / 0 は Infinity、数学.商(7, 0) は「0 で割れません」。
なし + 1 は「なしでは計算できません」(文字列とつなぐと 빈값 と表示)、ない名前は「まだ作られていません」

よくある間違い

i <= n で 1 つはみ出したC · C++ · Java · C# · JavaScript · TypeScript

int sum = 0;
for (int i = 0; i <= n; i++)
    sum += a[i];

→ Java・C# は範囲外の例外、JavaScript は undefined を足して NaN、C は黙ってごみの値を足します

i < n と書きます。

== の代わりに = を書いたC · C++ · JavaScript

if (x = 5) {
    puts("five");
}

→ エラーなしで x に 5 が入り、いつも真になります(gcc -Wall なら警告してくれます)

比較は ==。
Java・C# はコンパイルエラー、Python は SyntaxError(3.10 からは "Maybe you meant '=='")、Craykon は文法エラーで止めてくれます。

平均が整数になったJava · C# · C · C++

int sum = 7, n = 2;
double avg = sum / n;

→ avg は 3.0 です。7 / 2 が整数の割り算なので、小数が先に捨てられます

片方を浮動小数点数にします:(double)sum / n。

言語ごとの違い
エラーで止まるのは、むしろありがたいことです。
本当に怖いのは、C・C++ の範囲外アクセスや JavaScript の undefined のようにエラーなしで間違った値が出る場合です。

練習問題