1.2.8. Python での例外処理¶
これまでの全てのコマンドを打ち込んでいれば、何度か例外送出を経験しているでしょう。例えばコマンドを打ち間違えると例外が送出されます。
Python コードを実行するといろいろな種類のエラーにより例外が送出されます. ソースコードの中では例外を捉えたり, カスタマイズしたエラー型を定義できます. 正しい例外型を探しているときには、the built-in Exceptions の記述に目を通すといいでしょう。
1.2.8.1. 例外¶
Python ではエラーは例外を送出します:
In [1]: 1/0
---------------------------------------------------------------------------
ZeroDivisionError: integer division or modulo by zero
In [2]: 1 + 'e'
---------------------------------------------------------------------------
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [3]: d = {1:1, 2:2}
In [4]: d[3]
---------------------------------------------------------------------------
KeyError: 3
In [5]: l = [1, 2, 3]
In [6]: l[4]
---------------------------------------------------------------------------
IndexError: list index out of range
In [7]: l.foobar
---------------------------------------------------------------------------
AttributeError: 'list' object has no attribute 'foobar'
ご覧の通り、異なるエラーは 異なる例外型 を送出します.
1.2.8.2. 例外を捉える¶
1.2.8.2.1. try/except¶
In [10]: while True:
....: try:
....: x = int(raw_input('Please enter a number: '))
....: break
....: except ValueError:
....: print('That was no valid number. Try again...')
....:
Please enter a number: a
That was no valid number. Try again...
Please enter a number: 1
In [9]: x
Out[9]: 1
1.2.8.2.2. try/finally¶
In [10]: try:
....: x = int(raw_input('Please enter a number: '))
....: finally:
....: print('Thank you for your input')
....:
....:
Please enter a number: a
Thank you for your input
---------------------------------------------------------------------------
ValueError: invalid literal for int() with base 10: 'a'
リソース管理で重要(例 ファイルを閉じる)
1.2.8.2.3. 許可を得るより謝る方が簡単¶
In [11]: def print_sorted(collection):
....: try:
....: collection.sort()
....: except AttributeError:
....: pass
....: print(collection)
....:
....:
In [12]: print_sorted([1, 3, 2])
[1, 2, 3]
In [13]: print_sorted(set((1, 3, 2)))
set([1, 2, 3])
In [14]: print_sorted('132')
132
1.2.8.3. 例外を送出する¶
例外を捉えて再送出する:
In [15]: def filter_name(name): ....: try: ....: name = name.encode('ascii') ....: except UnicodeError, e: ....: if name == 'Gaël': ....: print('OK, Gaël') ....: else: ....: raise e ....: return name ....: In [16]: filter_name('Gaël') OK, Gaël Out[16]: 'Ga\xc3\xabl' In [17]: filter_name('Stéfan') --------------------------------------------------------------------------- UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128)
コードのある部分をパスするための例外:
In [17]: def achilles_arrow(x): ....: if abs(x - 1) < 1e-3: ....: raise StopIteration ....: x = 1 - (1-x)/2. ....: return x ....: In [18]: x = 0 In [19]: while True: ....: try: ....: x = achilles_arrow(x) ....: except StopIteration: ....: break ....: ....: In [20]: x Out[20]: 0.9990234375
特定の状況に遭遇した(例 StopIteration)ことや特定の状況に遭遇していない状況 (例 カスタマイズしたエラー)を通知するために例外を使いましょう