例外の処理
ポイント
- まずtryを実行し、例外が発生されなければそのまま終了
- 例外が発生した時点でtry節の残りがスキップされ、exceptで該当の型が定義されていればそのexcept節が実行される
- 例外の型がexceptで定義した名前と一致しない場合、例外はさらに外側にあるtry文に渡される
- ハンドラが見つからない場合は例外のメッセージを表示し、実行終了する
- except節は例外名を省略するとき、全部の例外を対象にすることができる(あまり良い方法ではない)
import sys
try:
    f = open('myfile.txt')
    s = f.readline()
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("データが整数に変換できません。")
except:
    print("予期せぬエラー: ", sys.exc_info()[0])
    raise # 呼び出し元でキャッチできるように例外を再送出
- タプルを使うと1つのexcept節で複数の例外を指定することができる
複数の種類の例外をキャッチ
except(RuntimeError, TypeError, NameError):
    pass
- else節を使用することでtry節で例外が発生しなかった場合のみ実行する処理を書くことができる
- また、except 例外名 as errのように記載するとerrには例外インスタンスが渡される
- 例外名はerr.__str__()で参照可能
else節を追加
import sys
try:
    f = open('myfile.txt')
    s = f.readline()
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("データが整数に変換できません。")
except:
    print("予期せぬエラー: ", sys.exc_info()[0])
    raise # 呼び出し元でキャッチできるように例外を再送出
else:
    print(s)
    f.close()
例外を起こす
ポイント
- 
raise 例外名(引数)で例外を強制的に発生させられる
- except節内で単にraiseと書くと例外を再送出できる
例外を定義する
ポイント
- 例外クラスを作成すると独自の例外を定義できる
- 通常は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 as e:
    print('My exception occurred, value:', e.value)
# 出力
# My exception occurred, value: 4
raise MyError('oops!')
# 出力
# Traceback (most recent call last):
#   File ".\exception_class.py", line 12, in <module>
#     raise MyError('oops!')
# __main__.MyError: 'oops!'
try-finallyでクリーンアップ処理
ポイント
- finally節は、例外発生の有無にかかわらず、tryを抜けるときに必ず実行される
- try文内の他の節からbreak, continue, return文によって抜けるときも実行される
finallyの例
def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("ゼロ除算エラー")
    else:
        print('答え: ', result)
    finally:
        print('in finally')
divide(2, 1)
# 答え:  2.0
# in finally
divide(2, 0)
# ゼロ除算エラー
# in finally
divide("2", "1")
# in finally
# Traceback (most recent call last):
#   File ".\divide.py", line 15, in <module>
#     divide("2", "1")
#   File ".\divide.py", line 3, in divide
#     result = x / y
# TypeError: unsupported operand type(s) for /: 'str' and 'str'
withでクリーンアップ処理
ポイント
- オブジェクトには標準のクリーンアップ動作が定義してあるものがある(例えばファイルオブジェクトなど)
- with文を使う事でデフォルトのクリーンアップ処理が自動的に実行される
with open('workfile', 'r') as f:
    read_data = f.read()
print(f.closed)
# True