#!/usr/bin/env python
# coding: utf-8
# # 例外
# ## 例外の捕捉
# 以下のコードは数値を$0$で割るため、実行するとエラー(例外)が発生する。
# In[1]:
2. / 0
# プログラム中でエラーが発生したときは、例外クラスのオブジェクトが作成・送出される。例えば、上の例では[ZeroDivisionError](https://docs.python.org/ja/3/library/exceptions.html#ZeroDivisionError)という例外クラスのオブジェクトが`'float division by zero'`というメッセージ付きで送出されている。
#
# プログラムの実行中に例外が発生するとPythonインタプリタの実行が直ちに停止されるが、 [try](https://docs.python.org/ja/3/reference/compound_stmts.html#the-try-statement)文およびexcept節を用いて、例外をプログラム中で捕捉することも可能である。
# In[2]:
try:
2. / 0
except ZeroDivisionError as e:
print('ゼロ除算:', e)
# try文を用いても、except節で指定した例外クラス以外の例外が発生した場合は、except節は実行されずPythonインタプリタの実行が止まってしまう。以下のプログラムで発生する例外は[OverflowError](https://docs.python.org/ja/3/library/exceptions.html#OverflowError)であるため、ZeroDivisionErrorに関するexcept節では捕捉しきれない。
# In[3]:
try:
2. ** 1024
except ZeroDivisionError as e:
print(e)
# except節を複数並べることで、異なる複数の例外に対する処理を記述できる。
# In[4]:
try:
2. ** 1024
except ZeroDivisionError as e:
print('ゼロ除算:', e)
except OverflowError as e:
print('オーバーフロー:', e)
# In[5]:
try:
2. / 0
except ZeroDivisionError as e:
print('ゼロ除算:', e)
except OverflowError as e:
print('オーバーフロー:', e)
# except節に例外クラスをタプルとしてまとめることで、異なる複数の例外に対する処理をまとめて記述できる。
# In[6]:
try:
2. ** 1024
except (ZeroDivisionError, OverflowError) as e:
print('例外:', type(e), e)
# In[7]:
try:
2. / 0
except (ZeroDivisionError, OverflowError) as e:
print('例外:', type(e), e)
# なお、ZeroDivisionErrorやOverflowErrorなどの組み込み例外の基底クラスは[Exception](https://docs.python.org/ja/3/library/exceptions.html#Exception)であるため、except節でExceptionクラスを指定すると、異なる種類の例外をまとめて捕捉できる。
# In[8]:
try:
2. ** 1024
except Exception as e:
print('例外:', type(e), e)
# In[9]:
try:
2. / 0
except Exception as e:
print('例外:', type(e), e)
# ## 例外の送出
# [raise](https://docs.python.org/ja/3/reference/simple_stmts.html#raise)文を用いると、自分で実装したコードの中から例外を送出できる。
# In[10]:
def timestamp(hour, minute, second):
if hour < 0 or 24 <= hour:
raise ValueError("引数hourは0 <= hour < 24を満たす必要があります")
if minute < 0 or 60 <= minute:
raise ValueError("引数minuteは0 <= minute < 60を満たす必要があります")
if second < 0 or 60 <= second:
raise ValueError("引数secondは0 <= second < 60を満たす必要があります")
return hour * 3600 + minute * 60 + second
# In[11]:
timestamp(2, 43, 70)
# 関数の呼び出し側にtry文を埋め込み、例外を捕捉することも可能である。
# In[12]:
try:
timestamp(48, 0, 0)
except Exception as e:
print('例外:', type(e), e)
# 例外クラスを自分で定義することもできる。ユーザ定義の例外クラスは[Exception](https://docs.python.org/ja/3/library/exceptions.html#Exception)を継承する必要がある。
# In[13]:
class TimestampError(Exception):
pass
def timestamp(hour, minute, second):
if hour < 0 or 24 <= hour:
raise TimestampError("引数hourは0 <= hour < 24を満たす必要があります")
if minute < 0 or 60 <= minute:
raise TimestampError("引数minuteは0 <= minute < 60を満たす必要があります")
if second < 0 or 60 <= second:
raise TimestampError("引数secondは0 <= second < 60を満たす必要があります")
return hour * 3600 + minute * 60 + second
# In[14]:
timestamp(1, 95, 22)
# 今回の引数チェックの場合、`hour`, `minute`, `second`のそれぞれに対し、別の例外クラスを定義するのも一案である。
# In[15]:
class TimestampError(Exception):
pass
class TimestampHourError(TimestampError):
pass
class TimestampMinuteError(TimestampError):
pass
class TimestampSecondError(TimestampError):
pass
def timestamp(hour, minute, second):
if hour < 0 or 24 <= hour:
raise TimestampHourError("引数hourは0 <= hour < 24を満たす必要があります")
if minute < 0 or 60 <= minute:
raise TimestampMinuteError("引数minuteは0 <= minute < 60を満たす必要があります")
if second < 0 or 60 <= second:
raise TimestampSecondError("引数secondは0 <= second < 60を満たす必要があります")
return hour * 3600 + minute * 60 + second
# In[16]:
try:
timestamp(2, 68, 0)
except Exception as e:
print('例外:', type(e), e)
# なお、デバッグ目的であれば[assert](https://docs.python.org/ja/3/reference/simple_stmts.html#the-assert-statement)文を使い、引数の値をチェック(テスト)して、違反していたら[AssertionError](https://docs.python.org/ja/3/library/exceptions.html#AssertionError)を送出することもできる。
# In[17]:
def timestamp(hour, minute, second):
assert 0 <= hour < 24, "引数hourは0 <= hour < 24を満たす必要があります"
assert 0 <= minute < 60, "引数minuteは0 <= minute < 60を満たす必要があります"
assert 0 <= second < 60, "引数secondは0 <= second < 60を満たす必要があります"
return hour * 3600 + minute * 60 + second
# In[18]:
timestamp(2, 43, 70)
# ## よく見かける例外
# 文法エラー
# In[19]:
2 / / 1
# インデントの間違い
# In[20]:
for i in range(10):
if i % 2 == 0:
print('even')
# オーバーフロー
# In[21]:
2. ** 1024
# 未定義の変数
# In[22]:
a * 2
# 範囲外のインデックス
# In[23]:
x = [1, 2, 3]
x[4]
# キーが見つからない
# In[24]:
y = {'one': 1, 'two': 2, 'three': 3}
y['four']
# 型の不整合
# In[25]:
x + y
# ファイルが見つからない
# In[26]:
open('hoge.txt')
# ---
#
# [Python早見帳](https://chokkan.github.io/python/) © Copyright 2020-2022 by [岡崎 直観 (Naoaki Okazaki)](https://www.chokkan.org/). この作品はクリエイティブ・コモンズ 表示 - 非営利 - 改変禁止 4.0 国際 ライセンスの下に提供されています。