Pythonでは、プログラム実行中にエラーが発生すると例外(Exception)が発生し、処理が中断されます。
標準で用意された例外だけでなく、アプリケーションの要件に合わせて「独自例外」を作成することで、エラー原因をより明確にし、保守性や可読性を向上させることができます。
本記事では、初級者向けに例外処理の基本から独自例外の作成方法、使い方、演習問題と解答例までを丁寧に解説します。
例外処理の基本
try–except–finally 構文
try:
# エラーが発生するかもしれない処理
result = 10 / 0
except ZeroDivisionError as e:
# ZeroDivisionError が発生したときの処理
print(f"エラーが発生しました: {e}")
finally:
# 例外の有無にかかわらず必ず実行される処理
print("処理を終了します")
- try ブロック:通常処理を記述
- except ブロック:特定の例外発生時の処理
- finally ブロック:後片付け等、必ず実行したい処理
except の応用
複数の例外をまとめてキャッチしたり、例外オブジェクトに名前を付けて詳しい情報を取得できます。
try:
x = int(input("整数を入力してください: "))
print(10 / x)
except (ValueError, ZeroDivisionError) as err:
print(f"入力または計算エラー: {err}")
独自例外を作成するメリット
- 可読性の向上
意図にあった例外クラス名にすることで、何のエラーか一目瞭然になる。 - 細かいエラー管理
既存の例外と区別してcatchできる。 - 再利用性
プロジェクト内で共通的に使える例外クラスとしてまとめられる。
独自例外の作り方
- Exceptionクラスを継承
- 必要に応じて __init__ や属性を定義
- raise文で発生させる
シンプルな独自例外
class MyError(Exception):
"""汎用的な独自例外クラス"""
pass
def func(x):
if x < 0:
# 条件を満たしたら MyError を発生
raise MyError("x は 0 以上でなければなりません")
return x
try:
func(-5)
except MyError as e:
print(f"独自例外キャッチ: {e}")
詳細情報を持たせる例外
class ValidationError(Exception):
def __init__(self, message, value):
super().__init__(message)
self.value = value # 問題となった値を保持
def validate_age(age):
if age < 0 or age > 120:
raise ValidationError("年齢の範囲が不正です", age)
try:
validate_age(150)
except ValidationError as e:
print(f"{e}: 問題の値 = {e.value}")
実践例:ユーザー入力のバリデーション
以下は、ユーザーIDとして正の整数のみを許可する例です。
class InvalidUserIDError(Exception):
"""ユーザーIDが不正な場合に発生する例外"""
def __init__(self, user_id):
super().__init__(f"ユーザーID {user_id} は正の整数でなければなりません")
self.user_id = user_id
def register_user(user_id):
if not isinstance(user_id, int) or user_id <= 0:
raise InvalidUserIDError(user_id)
print(f"ユーザー {user_id} を登録しました")
# 使用例
try:
register_user(-1)
except InvalidUserIDError as e:
print(f"登録失敗: {e}")
演習問題
問題1
ユーザー名として、3文字以上20文字以下かつ英数字のみを許可する InvalidUsernameError クラスを作成し、バリデーション関数 validate_username(username) を実装してください。
問題2
ポート番号として 1~65535 の整数のみを許可する InvalidPortError クラスを作成し、関数 check_port(port) を実装してください。
無効な場合は例外を発生させ、呼び出し側でキャッチしてエラーメッセージを表示してください。
解答例
解答1
class InvalidUsernameError(Exception):
def __init__(self, username):
super().__init__(f"ユーザー名『{username}』は3文字以上20文字以下の英数字で入力してください")
self.username = username
import re
def validate_username(username):
if not (3 <= len(username) <= 20):
raise InvalidUsernameError(username)
if not re.match(r'^[A-Za-z0-9]+$', username):
raise InvalidUsernameError(username)
return True
# テスト
for name in ["ab", "validUser123", "invalid_user!", "thisnameiswaytoolong123"]:
try:
validate_username(name)
print(f"{name}: OK")
except InvalidUsernameError as e:
print(f"{name}: {e}")
解答2
class InvalidPortError(Exception):
def __init__(self, port):
super().__init__(f"ポート番号 {port} は 1~65535 の範囲で指定してください")
self.port = port
def check_port(port):
if not isinstance(port, int) or not (1 <= port <= 65535):
raise InvalidPortError(port)
print(f"ポート {port} を使用します")
# テスト
for p in [0, 22, 70000, "80"]:
try:
check_port(p)
except InvalidPortError as e:
print(f"エラー: {e}")
まとめ
- 例外処理 でプログラムの安定性を確保
- 独自例外 を作ることで、エラー原因が明確に
- 演習問題 で理解を深める
今回学んだ独自例外の作成方法を活用し、より堅牢で読みやすいコードを目指しましょう!