今までエラーメッセージについてはせいぜい言及するだけだったが、 もしもいままでの例を実際に試してきたなら、おそらく例外のいくつかを見ていることだろう。 エラーは (少なくとも) 構文エラー (syntax error) と例外 (exception) の二つに大別できる。
構文エラーは構文解析エラー (parsing error) としても知られる。 これはもしかすると Python を学んでいるあいだに発生する問題の うち最もありふれた種類のものかもしれない。
>>> while True print 'Hello world' File "<stdin>", line 1, in ? while True 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 by zero >>> 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: cannot concatenate 'str' and 'int' objects
エラーメッセージの最後の行は、何が起こったかを示している。 例外はさまざまな型 (type) で発生し、その型はメッセージの一部として印字される。 例で挙げられている型は ZeroDivisionError, NameError, TypeError だ。 例外型として印字される文字列は、発生した例外を表す組込み名の名前だ。 これはすべての組込み例外について成り立つが、 利用者定義の例外については必ずしも成り立たない (しかし、有用な慣習だ)。 標準例外名は組込み識別子だ (予約語ではない)。
行の残りは詳細説明で、その解釈は例外型に依存する。 その意味は例外型によって決まる。
それより前の部分のエラーメッセージは、例外が起こった文脈を、 スタックバックトレース (stack backtrace) の形式で示している。 一般にこれはソース行をリストするスタックバックトレースからなるが、 標準入力から読み取られた行は表示されない。
Python Library Reference は組込み例外とその意味をリストしている。
例外を選んで処理するプログラムを書くことができる。 次の例を見よう。 これは正しく整数が入れられるまで利用者に入力を求める。ただし、 利用者が (Control-C または何であれオペレーティングシステムがサポート しているキーを使って) プログラムを中断することもできる。 利用者が発生させた中断は、KeyboardInterrupt 例外の ひき起こしによって合図されることに注意しよう。
>>> while True: ... 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 節は例外名(あるいはリスト)の後に変数を指定してもよい。
instance.args
の中に引数が格納され、この変数は例外インスタンス
と結び付けられる。
.args
に参照を付ける必要なしに、引数に直接アクセスするか印字す
ることができる利便性のために、例外インスタンスは __getitem__
と __str__ を実装している。
>>> try: ... raise Exception('spam', 'eggs') ... except Exception, inst: ... print type(inst) # 例外インスタンス ... print inst.args # .argsに引数が格納される ... print inst # __str__ はargsの中身を直接印字する事ができる ... x, y = inst # __getitem__ はargsの中身をを直接分解する事ができる ... print 'x =', x ... print 'y =', y ... <type 'instance'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
もしも例外に引数があれば、それは、処理されない例外に対するメッセージの 最後の部分 (`詳細説明') として印字される。
例外ハンドラは、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.