1-4. デバッグ

デバッグについて説明します。

参考

プログラムにバグ(誤り)があって正しく実行できないときは、バグを取り除くデバッグの作業が必要になります。

エラーには大きく分けて、文法エラー実行エラー論理エラーがあります。以下、それぞれのエラーについて対処法を説明します。 また print を用いたデバッグについても紹介します。

文法エラー:Syntax Errors

文法エラーは、入力がPythonの文法に違反しているエラーです。 文法エラーに対しては、

  1. まず、エラーメッセージを確認しましょう。

  2. エラーメッセージの最終行を見て、それが SyntaxError であることを確認しましょう。

  3. エラーとなっているコードの行数を確認しましょう。

  4. そして、当該行付近のコードを注意深く確認しましょう。

よくある文法エラーの例:

  • クォーテーションや括弧の閉じ忘れ

  • コロンのつけ忘れ

  • === の混同

  • インデントの誤り

  • 全角の空白

など

[1]:
print("This is the error)
  File "/tmp/ipykernel_1661/2920420528.py", line 1
    print("This is the error)
                             ^
SyntaxError: EOL while scanning string literal

[2]:
1 + 1
  File "/tmp/ipykernel_1661/602967778.py", line 1
    1 + 1
        ^
SyntaxError: invalid character in identifier

実行エラー:Runtime Errors

実行エラーは、コードの実行時に検出されるエラーです。 実行エラーに対しては、

  1. まず、エラーメッセージを確認しましょう。

  2. エラーメッセージの最終行を見て、そのエラーのタイプを確認しましょう。

  3. エラーとなっているコードの行数を確認しましょう。

  4. そして、当該行付近のコードについて、どの部分が実行エラーのタイプに関係しているか確認しましょう。もし複数の原因がありそうであれば、行を分割、改行して再度実行し、エラーを確認しましょう。

  5. 原因がわからない場合は、 print を挿入して処理の入出力の内容を確認しましょう。

よくある実行エラーの例:

  • 文字列やリストの要素エラー

  • 変数名・関数名の打ち間違え

  • 無限の繰り返し

  • 型と処理の不整合

  • ゼロによる割り算

  • ファイルの入出力誤り

など

[3]:
print(1/0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
/tmp/ipykernel_1661/165659023.py in <module>
----> 1 print(1/0)

ZeroDivisionError: division by zero

論理エラー:Logical Errors

論理エラーとは、プログラムを実行できるが、プログラムが意図したように動作しないというエラーです。 論理エラーに対しては、

  1. 入力に対する期待される出力と実際の出力を確認しましょう。

  2. コードを読み進めながら、期待する処理と異なるところを見つけましょう。必要であれば、 print を挿入して処理の入出力の内容を確認しましょう。

コーディングスタイル

実は、生じたバグを取る対処法よりも、そもそもバグが生じにくくする予防法の方が大切です。 Pythonにおいて特に重要視されているのが、コーディングスタイル、つまりコードの書き方です。 読みにくい(可読性の低い)コードだと、些細なミスが生じやすく、また見つけにくいからです。

PythonではPEP8非公式日本語訳)と呼ばれる公式のスタイルガイドがあります。 PEP8には様々な側面でスタイルに関する規則があり、コードの可読性を高めることが強く推奨されています。 ここまでに扱った言語の要素について、たとえば、

  • インデントは半角スペースを4つで1レベル

  • = += == などの演算子の前後に半角スペースを1つ入れる

  • *+ の複合式では + の前後に半角スペースを1つ入れる(例:2*x + y

  • 関数の開き括弧の前にスペースを入れない

  • l I O を変数名として使わない

  • 真理値の比較に ==is を使わない

などが代表的です。

PEP8に基づいたコーディングスタイルの自動検査器もあります(参照:pycodestyle)。 オンラインサービスもいくつか利用できるので(例:PEP8 online)、適宜活用してみましょう。

PEP8には陽に言及されていないもの、プログラミング一般に重要なこともあります。 たとえば、

  • 自己説明的でない“マジックナンバー”ではなく記号的に意味がわかる変数を使う

  • 不要なコードは削除する

  • 1つの関数では1つのタスクだけを処理する

などは、可読性を上げる代表的なポイントです。

勘違いはバグを引き起こします。自らが勘違いしないコードを書くことが肝要です。

▲assert文によるデバッグ

論理エラーを見つける上で有用なのが、assert文です。 assert の次に書かれた条件式が偽であった時に、AssertionError が発生してプログラムが停止する仕組みです。 次に例を示します。

[12]:
import math
def sqrt(x):
    assert x >= 0
    return math.sqrt(x)

sqrt(2)
sqrt(-2)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
/tmp/ipykernel_1661/3580709644.py in <module>
      5
      6 sqrt(2)
----> 7 sqrt(-2)

/tmp/ipykernel_1661/3580709644.py in sqrt(x)
      1 import math
      2 def sqrt(x):
----> 3     assert x >= 0
      4     return math.sqrt(x)
      5

AssertionError:

ここで定義した sqrt 関数は、平方根を求める関数です。 非負の数しかとらないことを前提とした関数なので、 この前提を assert x >= 0 としてプログラムの中で記述しています。 sqrt(2) の呼び出しでは、この前提は満たされ、問題なく計算が進みます。

しかし、sqrt(-2) の呼び出しでは、この前提が満たされないため、assert文が AssertionError を出します。 このエラーメッセージによって、どの部分のどのような前提が満たされなかったかが簡単にわかります。 これは、論理エラーの原因の絞り込みに役立ちます。

[ ]: