feature/me

勉強したこととかをまとめる

例外処理(Exception handling)について

例外とは

特定の入力があったときに、予期せぬ処理をしないようにあらかじめ動作を指定しておくことです。 簡単に言うと、正しいプログラムが動作しているときに起こるエラーを処理することです。(Syntax Errorは正しくないプログラムなので違う)

基本的にデバッグ中はエラーを吐いても、エラー文から修正箇所を特定すれば良いですが、実際の運用ではエラーが起きてプログラム全体が落ちるなんてことはあってはならないです。

そこで、そのようなエラーを発生しうるコードの箇所に「もし〇〇の例外が発生したら~」と記述することを例外処理と言います。

よくある例外

  • ZeroDivisionError : 1/0のようにゼロで割ってしまったときに起こる
  • TypeError : 演算や関数で使えない型で入力されたときに起こる(文字列どうしで割り算したりすると起こる)
  • ValueError : 期待する範囲外の数が入力されたときに起こる
  • OSError : 要求されたファイルやディレクトリが存在しないときに起こる

その他のエラーは5. 組み込み例外 ー Python3 ドキュメントを参照してください。

例外処理

基本的にtry文で処理されます。

try: 
    # 実行する処理
except 例外の指定:
    # 実行時に例外が起きたときの処理

まず、try節(try と except の間の文)が実行されます。そこで何も例外が発生しなければ、except節をスキップしてtry文の実行を終えます。

try節内の実行中に例外が発生すると、その節の残りは飛ばされ、例外型がexceptの後に指定されている例外に一致する場合、except節が実行された後、try文の後ろへ実行が継続されます。

expect節では適切な例外を指定しないと、正しく処理されません。かと言って、exceptの後に例外を指定しないことも推奨されていません。考えられる例外は全て正しく処理させましょう。

try:
    f = open('myfile.txt', 'r', encoding='utf-8')
    s = f.read()
    f.close()
    i = int(s)
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")

また、ひとつのtry文には複数のexcept節を持たせることも可能です。

...except (OSError, TypeError, ValueError) as err:
...    print(err)

このようにさまざまな例外に対応させることができます。

意図的に例外を発生させる

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 <module>
NameError: HiThere

(いつ使うかは正直よくわからない...)

try文のその他の節

try文のもうひとつの節、finally節は、例外が発生したかどうかに関わらず、try文を抜ける前に必ず実行されます。

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
finally:
    print('Goodbye, world!')

実行結果

An exception flew by!
Goodbye, world!

else節も使えます。この場合、except節より後に置く必要があります。else節はtry節で全く例外が発生しなかったときに実行されるコードです。

def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("division by zero!")
    else:
        print("result is", result)
    finally:
        print("executing finally clause")

実行結果

>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

References