今までエラー・メッセージについてはせいぜい言及するだけだったが, もしも君が例を試してきたならば,おそらくそのいくつかを見ていることだろう。 エラーは (少なくとも) 二つに大別できる。それは 構文エラー (syntax error) と例外 (exception) である。
構文エラーは構文解析エラー (parsing error) としても知られる。 これはもしかすると君が Python を学んでいるあいだに受ける苦情の うち最もありふれた種類のものかもしれない。
>>> while 1 print 'Hello world' File "<stdin>", line 1, in ? while 1 print 'Hello world' ^ SyntaxError: invalid syntax
パーサは構文違反の行を繰り返し, その行の中でエラーが検出された最初の位置を指す小さな「矢印」を表示する。 エラーは矢印の直前のトークンでひき起こされている (か,少なくとも そこで検出されている)。 この例ではエラーはキーワード print で検出されている。 これはコロン (":") がその前に無いからである。 入力がスクリプトから来ている場合は, どこを見ればよいか分かるようにファイル名と行番号が印字される。
文や式が構文的に正しくても, それを実行しようとした時にエラーが起こるかもしれない。 実行中に検出されるエラーは例外と呼ばれる。 例外は無条件に致命的なわけではない。 君はすぐ後で Python プログラム内で例外を処理する方法を学ぶことになる。 とはいっても,たいていの例外はプログラムで処理されず, ここに示すようなエラー・メッセージに終わる。
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: illegal argument type for built-in operation
エラー・メッセージの最後の行は,何が起こったかを示している。 例外はさまざまな型 (type) で到来し,その型はメッセージの一部として印字される。 例で挙げられている型は ZeroDivisionError, NameError, TypeError である。 例外型として印字される文字列は,発生した例外を表す組込み名の名前である。 これはすべての組込み例外について成り立つが, 利用者定義の例外については必ずしも成り立たない (しかし,有用な慣習である)。 標準例外名は組込み識別子である (予約語ではない)。
行の残りは詳細説明であり,その解釈は例外型に依存する。 その意味は例外型によって決まる。
それより前の部分のエラー・メッセージは,例外が起こった文脈を, スタック・バックトレース (stack backtrace) の形式で示している。 一般にこれはソース行をリストするスタック・バックトレースからなるが, 標準入力から読み取られた行は表示されない。
Python Library Reference は組込み例外とその意味をリストしている。
例外を選んで処理するプログラムを書くことができる。 次の例を見よう。 これは正しく整数が入れられるまで利用者に入力を求める。ただし, 利用者が (Control-C または何であれオペレーティング・システムがサポート しているキーを使って) プログラムを中断することもできる。 利用者が発生させた中断は,KeyboardInterrupt 例外の ひき起こしによって合図されることに注意しよう。
>>> while 1: ... try: ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: ... print "Oops! That was no valid number. Try again..." ...
try 文は下記のように働く。
一つの try 文に複数の except 節を設けて, さまざまな例外に対するハンドラを指定してもよい。 たかだか一つのハンドラが実行される。 ハンドラは,対応する try 節の中で発生した例外を処理するだけであり, 同じ try 文のほかのハンドラで発生した例外は処理しない。 一つの except 節で,複数の例外を,丸かっこで囲んだ並びとして指定してもよい。 たとえば,
... except (RuntimeError, TypeError, NameError): ... pass
最後の except 節は例外名を省いてもよい。 これはワイルドカードとして働く。 これは極度に注意して使おう。なぜなら, こうすると本物のプログラミング・エラーがたやすく隠されてしまうからだ! これは,エラー・メッセージを印字して, そしてそれから (呼出し元が同様に例外を処理できるように) 例外を 再発生させることにも使える。たとえば,
import string, sys try: f = open('myfile.txt') s = f.readline() i = int(string.strip(s)) except IOError, (errno, strerror): print "I/O error(%s): %s" % (errno, strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise
try ... except 文に else 節 (else clause) を設けてもよい。 もし設けるとすれば,すべての except 節の次でなければならない。 これは,try 節が例外をひき起こさなかったときに 実行しなければならないコードとして役立つ。 たとえば,
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
else 節を使うほうが,try 節にコードを追加するよりも良い。 なぜなら, try ... except 文で保護されているコードによって ひき起こされたのではない例外をたまたま捕獲してしまう, ということを避けられるからだ。
例外が発生した時,その例外には一つの値,例外の引数 (argument) としても 知られる値が,結合しているかもしれない。 引数の有無とその型は,例外型によって決まる。 引数をもつ例外型のために,except 節は,引数値を受けとる変数を, 例外の名前 (またはその並び) の後に,下記のように指定してもよい。
>>> try: ... spam() ... except NameError, x: ... print 'name', x, 'undefined' ... name spam undefined
もしも例外に引数があれば,それは,処理されない例外に対するメッセージの 最後の部分 (`詳細説明') として印字される。
例外ハンドラは,try 節でじかに発生した例外だけではなく, その try 節から (間接的にであれ) 呼び出された関数の内部で発生した例外も 処理する。たとえば,
>>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError, detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo
raise 文は,プログラマが, 指定した例外を強制的に発生させることを可能にしている。たとえば,
>>> raise NameError, 'HiThere' Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: HiThere
raise の第1引数は,ひき起こすべき例外を指名する。 省略可能な第2引数は,例外の引数を指定する。
例外が発生したかどうか断定する必要があるが,必要であると判断するなら, raise ステートメントのより単純な形式は,君が再度例外を発生さ せる事を可能にする。
>>> try: ... raise NameError, 'HiThere' ... except NameError: ... print 'An exception flew by!' ... raise ... An exception flew by! Traceback (most recent call last): File "<stdin>", line 2, in ? NameError: HiThere
プログラムは新しい例外クラスの作成により,独自の例外を指定してよい。 典型的な例外は, Exception クラスに直接あるいは間接的に由 来する必要がある。例えば
>>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MyError(2*2) ... except MyError, e: ... print 'My exception occurred, value:', e.value ... My exception occurred, value: 4 >>> raise MyError, 'oops!' Traceback (most recent call last): File "<stdin>", line 1, in ? __main__.MyError: 'oops!'
例外クラスは,他のクラスができる事をすべて定義することができるが, 普通は単純で,単に例外処理により取得されたエラーに関する情報を いくつか提示するだけにとどめておく。 いくつかの独自の例外を発生することができるモジュールを作成する場合,そ のモジュールで定義された例外のための基底クラスを作成し,異なる例外条件 のための特定の例外クラスを作成する時はサブクラスとして作成する事が共通 に行なわれる。
class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message
ほとんどの例外は標準の例外の命名と同様,``Error,'' で終わる名前で定義 される。
多くの標準のモジュールが,それらが定義する関数で発生するかもしれないエ ラーを報告するために独自の例外を定義している。 クラスについてのもっと多くの情報は第 9 章 ``クラス'' にある。
try 文にはもう一つ,いかなる状況下でも実行しなくてはならない 後片付け動作 (clean-up action) の定義を目的とする選択可能な節がある。 たとえば,
>>> try: ... raise KeyboardInterrupt ... finally: ... print 'Goodbye, world!' ... Goodbye, world! Traceback (most recent call last): File "<stdin>", line 2, in ? KeyboardInterrupt
finally 節 (finally clause) は, try 節で例外が発生したかどうかに関係なく実行される。 例外が発生した時は,finally 節を実行した後,再びその例外がひき起こされる。 try 文から break 文や return 文経由で 脱出する時にも,そこを ``出る途中で'' finally 節が実行される。
finally 節中のコードは資源の使用が成功したかどうかにかかわらず,(ファ イルあるいはネットワーク接続のような)外部資源を開放するのに役立つ。
try 文には,1個以上の except 節か, または1個の finally 節が必要だが,両方あってはならない。
See About this document... for information on suggesting changes.