こんにちは、Zero-Cheeseです。
本記事では、Pythonの例外処理について、詳しく解説しています。
コーディング中、しばしば予期しない問題に、直面します。
そんなときに役立つのが、例外処理です。
この記事を読むことで、
- 例外処理の基本を把握し、
- より堅牢なコードを書くための手法を習得する
事ができます。
- Python初心者の方(入門書を読み終わった程度の方)以上を
対象とした、内容となっています。
Pythonのエラーと例外処理
エラーの例外の違い
Pythonにおける「エラー」は、プログラムが期待通りに、動作しない状態を指します。
その中でも、「例外」は特定の状況で発生するエラーで、通常のフローを中断します。
しかし、これらの例外は適切に処理(例外処理)することで、プログラムの完全な停止を防ぐことができます。
より詳細な解説(中・上級者向け)
Pythonの、「エラー(Error)」と「例外(Exception)」は、
- プログラム実行中の「問題発生時」に、通知するためのメカニズムで、
正確にはすべて「例外」です。
しかし「エラー」という用語は、一般的な会話では、「予期せぬ」または「望ましくない動作」を指すため、本記事でもそのように紹介しております。
よく遭遇する例外の紹介(一部)
Pythonでよく遭遇する例外の一部を、ご紹介します。
ZeroDivisionError
: 数値を0で割ったときに発生TypeError
: 互換性のない型を操作しようとしたときに発生IndexError
: 範囲外のインデックスを指定したときに発生
上記は一例ですが、
- なぜ例外が発生したかを理解し、
- それに対応するための方法を学ぶことは、
堅牢なプログラム作りには、重要です。
次の章では、Pythonでの例外処理方法について、解説します。
Pythonの例外処理(try-except文)基本
本章では、Pythonで例外を処理するための
try-except
文の基本的な使い方
について解説します。
try-except文の基本
try-except
文の基本的な形式は、次のようになります:
try:
# 例外が発生する可能性があるコード
except ExceptionType:
# 例外が発生したときに実行するコード
上記のExceptionType
は、捕捉したい「例外の種類」を指します。
【具体例】 「ExceptionType」が、「ZeroDivisionError」の場合:
try:
x = 1 / 0
except ZeroDivisionError:
print("0で割ることはできません")
このコードでは、0で割るという操作がZeroDivisionError
を引き起こします。
try文を使用しないと、プログラムが停止します。
try-except
文を使用することでこの例外を捕捉し、適切に処理する事ができます。
複数の例外に対する処理の書き方
プログラムによっては、複数の種類の例外が、発生する可能性があります。
この場合、try-except
文を使って、複数の例外を個別に処理することができます:
try:
# 例外が発生する可能性があるコード
except ExceptionType1:
# ExceptionType1が発生したときに実行するコード
except ExceptionType2:
# ExceptionType2が発生したときに実行するコード
【具体例】
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("0で割ることはできません")
except TypeError:
print("数値以外のデータ型で、割り算はできません")
divide(1, 0) # ZeroDivisionErrorを引き起こします
divide("1", 2) # TypeErrorを引き起こします
Pythonの例外処理 応用 try-except-else-finally文と例外の送出(raise)
try-except-else-finally文
Pythonのtry-except
文は、else
句とfinally
句を追加することで、拡張することができます。
Pythonコードは以下の通りです。
try:
# 例外が発生する可能性があるコード
except ExceptionType:
# 例外が発生したときに実行するコード
else:
# 例外が発生しなかったときに実行するコード
finally:
# 例外の有無に関わらず実行するコード
else
句は、try
ブロックで、例外を発生しなかった場合のみ、実行されます。finally
句を使用すると、例外の有無に関わらず、特定のコードを実行できます。
このfinally
句は、例えばファイルやネットワーク接続のような、リソースをクリーンアップする場合、便利です。
【具体例】
def divide(x, y):
result = None
try:
result = x / y
except ZeroDivisionError:
print("0で割ることはできません")
except TypeError:
print("数値以外のデータ型で割り算はできません")
else:
print(f"結果は {result} です")
finally:
if result is None:
print("結果が得られませんでした")
else:
print("計算が完了しました")
divide(1, 0)
# 「0で割ることはできません 結果が得られませんでした」 (ZeroDivisionErrorが発生)
divide("1", 2)
# 「数値以外のデータ型で割り算はできません 結果が得られませんでした」 (TypeErrorが発生)
divide(4, 2) # 「結果は 2.0 です。 計算が完了しました。」
例外の送出(raise)
Pythonではraise
文を使って、自分で例外を、発生させることができます。
これは、プログラムの実行中に特定のエラー条件を検出した場合や、ユーザーに対して、何らかの問題を明示的に通知したい場合に有用です。
raise ExceptionType("エラーメッセージ")
【具体例】
def validate_age(age):
if not isinstance(age, int):
raise TypeError("年齢は整数で指定してください")
if age < 0:
raise ValueError("年齢は0以上である必要があります")
if age > 130:
raise ValueError("年齢が大きすぎます")
try:
validate_age("2")
except TypeError as e:
print(f"エラー: {e}")
try:
validate_age(-1)
except ValueError as e:
print(f"エラー: {e}")
try:
validate_age(200)
except ValueError as e:
print(f"エラー: {e}")
Pythonの例外処理 応用2 関数
関数やクラスを設計する際、
- 不正な値が入力された場合や、
- 予期せぬエラーが発生した場合に備えて、
例外処理を、適切に組み込みます。
関数が、Noneを返す場合
関数が直接「例外処理」を実行し、プログラムの他の部分に、影響を与えません。
その代わりに、適切なデフォルト値(この場合はNone)が返されます。
この方法は、エラーが致命的でない場合や、その場で処理できる場合に適しています。
【具体例】
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("エラー: 0で割ることはできません")
return None
return result
関数が、例外を伝搬させる場合
関数が例外を直接処理せずに、呼び出し元に、例外を伝える方法です。
これは、呼び出し元が、
- 例外を適切に処理する責任がある場合や、
- 例外が致命的でプログラムの実行を停止するべきである場合に、
適しています。
【具体例】
def divide(x, y):
if y == 0:
raise ZeroDivisionError("0で割ることはできません!")
return x / y
この場合、呼び出し元は適切な例外処理を行うために、try-except
文を使用しています。
【呼び出し元のコード】
try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"エラー: {e}")
Pythonの例外処理 応用3 オブジェクト指向
本章は、オブジェクト指向の知識がある方に向けた内容となっています。
少し、専門的な内容となっています。
オブジェクト指向は便利な一方で、クラス間の関係が複雑になりがちで、その複雑さを管理するのは容易ではありません。
デザインパターンや、様々なアーキテクチャーを駆使して、人間が理解しやすい設計を行いますが、本記事で紹介している例外も、重要な役割を果たします。
オブジェクト指向で使用される例外には、以下のような目的があります。
① 不適切なメソッドの使用を防ぐ
例えば、あるメソッドが特定の状況や条件下でのみ使用すべきである場合、それ以外のでは、例外を発生させるようにします。
下記の例では、open
メソッドが、unlock
メソッドが呼び出される前に呼び出されると、例外が発生します。
class LockedSafe:
def __init__(self):
self._is_locked = True
def unlock(self):
self._is_locked = False
def lock(self):
self._is_locked = True
def open(self):
if self._is_locked:
raise Exception("Safe is locked. Please unlock before opening.")
print("Safe is now open.")
# 使用例
safe = LockedSafe()
try:
safe.open()
except Exception as e:
print(f"Error: {e}")
② メソッドのパラメータをチェックする
メソッドの引数が、期待された範囲や型でない場合、例外を送出します。
下記の例では、Circle
クラスのコンストラクタが、負の数または数値でない引数を受け取ると、例外を送出しています。
class Circle:
def __init__(self, radius):
if not isinstance(radius, (int, float)) or radius <= 0:
raise ValueError("Radius引数が、負の数、もしくはint or float型ではありません。")
self.radius = radius
# 使用例
try:
circle = Circle(-5)
except ValueError as e:
print(f"Error: {e}")
③ クラスの不変性を守る
ある属性が変更されると、クラスの状態が無効になる場合、その変更を防ぐために例外を送出します。
class PositiveInteger:
def __init__(self, value):
if not isinstance(value, int) or value <= 0:
raise ValueError("Value must be a positive integer.")
self._value = value
# 使用例
num = PositiveInteger(5)
try:
num.value = -10
except ValueError as e:
print(f"Error: {e}")
上記クラスのコンストラクタでは、不適切なパラメータが渡された場合、例外が送出されます。
これにより、クラスが無効な状態になるのを、防ぐ事ができます。
まとめと注意点
try-exceptの重要性と役割の再確認
この記事では、
- try-except文の基本的な使い方から、
- 複数の例外の処理、
- さらには自分で例外を作成する方法まで、
さまざまな技術をご紹介しました。
これらの知識を活用すれば、予期せぬエラーが発生したときでも、プログラムを停止させずに、適切なフィードバックを得る事が、可能となります。
(場合によっては、プログラムを停止させるよう、設計できます。)
try-exceptを使う際の注意点
try-except文を活用する際には、特に注意すべき注意点が、2点あります。
1、具体的なエラーのタイプを指定せずに、全ての例外を捕捉するのは避けましょう。
これは、様々なエラーが発生する可能性がある中で、特定のエラーを見逃し、デバッグを困難にする可能性があるからです。
エラータイプを明示的に指定することで、それぞれのエラーに対する適切な対応が可能となります。
2、必要以上にtry-except文を使用することは、避けましょう。
これはコードの可読性を落とすだけでなく、予期せぬエラーを生じる可能性があるからです。
エラーが発生する可能性がある具体的な箇所だけに、「try-except文」を適用するよう、心掛けて下さい。
本記事も、最後までお付き合いいただき、ありがとうございました。
また、お会いしましょう!