過去にも少しだけ触れたが、もっと分かりやすく解説してくれている記事を見つけたので復習の意味も込めて。大先輩のブログより転載, aka all credit belongs to our legendary cs alumni
##Traceback message
Traceback (most recent call last):
File "<pyshell#29>", line 3 in <module>
result = buggy(5)
File <pyshell#29>", line 5 in buggy
return f + x
TypeError: unsupported operand type(s) for +: 'function' and 'int'
traceback messageのはエラーが起きた時系列順に経緯を辿ってプリントしてくれる。一番下が最も新しい。traceback messageは2つで一組の構成になっている。1つ目File "<pyshell#29>", line 3 in <module>
はエラーを含んでいるファイルの名前、どこに(何番目のライン)にそのエラーがあるのか、そしてそのエラーを含んでいる関数名の3つをFile "<file name>", line <number>, in <function>
というフォーマットで表している。2つ目result = buggy(5)
はそのままだがその実際のコードを表示している。
##Error messages
一番最後の行に書かれているのがerror messageである。error message<error type>: <error message>
はエラーの種類(syntaxerror, typeerror etc)とエラーの詳細のフォーマットで記載されている。
##Debugging
###Doctestでとりあえず動かしてみる
def foo(x):
"""A random function.
>>> foo(4)
4
>>> foo(5)
5
"""
terminal上よりpython3 -m doctest file.py
python3 -m doctest file.py -v
を使えばどのテストがパスしてどこが引っかかったかを教えてくれる。
通例としては最初の一行目で具体的にその関数が何をするのかを書き、一行ブランクを空ける。詳細な説明はこちら。
もしdoctest
の対象がsingle statement(=a single line that doesn't end in a :
)の場合は"run_docstring_examples"と呼ばれるdoctest
関数をつかう。この関数は3つの引数を持ちあわせている。1つめはテストしたい関数名、2つめはglobal()
(=a built-in function that returns the global environment)、そして3つめがTrue
(to indicate that we would like "verbose" output: a catalog of all tests run.)。ちなみにsingle statementをテストすることを__unit test__と呼ぶ。
Exhaustive unit testing is a hallmark of good program design.
- 良いプログラムデザインは包括的なunit testによって保証される。
それ以外にも自分自身でテスト関数を作ったり、新たにdoctestを作るってもよい。
Always run these doctests. Submitting an assignment without running doctests even once is practically throwing points away.
マジかよ。それは知らなかった(笑)
###要所要所にprint()を挟んで経過を確認
def foo(x):
result = some_function(x)
return result // 5
というコードを書いたとしてどこにエラーがあるのかわからない場合はとりあえず結果をprint
させてみる。
def foo(x):
result = some_function(x)
print('result is', result)
return other_function(result)
そしてできればただprint
させるのではなく一言加えておくと忘れずに済む
print(tmp) # harder to keep track
print('tmp was this:', tmp) # easier
while loopの後に入れるのも効果的
i = 0
while i < n:
i += func(i)
print('i is', i)
テストが終わったらprint
を消しておくのを忘れずに
##Long-term debugging
プロジェクト単位になってくると時にはデバグを瞬時に行わないほうがいい場合もある。そういうときは以下のようにしておくと便利
debug = True
def foo(n):
i = 0
while i < n:
i += func(i)
if debug:
print('i is', i)
もし毎回結果表示されるのが嫌ならばfalse
に変えてしまえばよい。こういった使い方をする変数をflag
と呼ぶ。
##Types of error
###Syntax Error
原因:
- コードに問題あり
File "file name", line number
def incorrect(f)
^
SyntaxError: invalid syntax
^
が不適切なシンタックスを含んでいるコードを示している。何がおかしいのかは表示されないがその原因がどこにあるかは教えてくれる。Pythonはコードを走らせる前にまずこのsyntax error
がないかを確認する。
###Indentation Error
原因:
- コードのラインのインデントに問題有り
File "file name", line number
print('improper indentation')
IndentationError: unindent does not match any outer indentation level
不適切にインデントがなされているところを表示している。スペースとタブの機能の区別をはっきりと。
###TypeError
原因:
- operand(max, mul etc..)とprimitive operator(数字など)の使い方が不適切の場合。
TypeError: unsupported operand type(s) for +: 'function' and 'int'
- 関数とオブジェクトがごっちゃになっている。
>>> square = 3
>>> square(3)
Traceback (most recent call last):
...
TypeError: 'int' object is not callable`
- 引数の数に問題有り。
>>> add(3)
Traceback (most recent call last):
...
TypeError: add expected 2 arguments, got 1
###NameError
原因:
- 定義されていない変数を使っているもしくは関数
File "file name", line number
y = x + 3
NameError: global name 'x' is not defined
notes: ここでglobal name
と記されている理由はPythonがエラーを含む関数のローカル領域から最終的にグローバル領域に入っていくためである。
###IndexError
原因:
- sequence(tuple, list, string)の渡せる数の限界を超えている。
File "file name", line number
x[100]
IndexError: tuple index out of range
##よくあるバグ
###simple spelling mistakes
hello
≠ Hello
≠ HELLO
ということ。NameError
と出てきた時はスペリングにミスがあるのかも。または間違えたスペリングで変数や関数を定義してしまっている場合もある。
###Missing Parentheses
そのまんま括弧のつけ忘れなど
def fun():
return foo(bar() # missing a parenthesis here
fun()
この場合、pythonはSyntaxError
と称し、括弧の問題がある行の一つ後の行を指す。
###Missing close quotes
pythonが具体的に教えてくれるので見つけるのも簡単。
File "file name", line "number"
return 'hi
^
SyntaxError: EOL while scanning string literal
EOL = "end of line"
###= (assignment) vs. == (equality test)
=
は変数を引き渡すときに、==
は変数が同等かどうかを確かめるために使う。典型的なエラーは
if x = 3: # when should be "==" instead
###Infinite Loops
whileループはそのコンディションが達成されるまで回り続けるので陥りやすい。
i = 0
while i < 10:
print(i)
i, n = 0, 0
while i < 10:
print(i)
n += 1