👌

Python インスタンス生成時の例外スローを回避する

2025/03/10に公開

Python インスタンス生成時の例外スローを回避する

通常、Python でクラスのインスタンスを生成する際、__init__ メソッド内で例外がスローされることがあります。しかし、特定の条件下でインスタンス生成を避けたい場合や、例外をスローせずに None を返したい場合があります。本記事では、これを実現する3つの方法を紹介します。

  • クラスメソッドを使う方法
  • ファクトリー関数を使う方法
  • __new__ を使う方法

1. クラスメソッドを使う方法

クラスメソッドを使うことで、インスタンス生成時のバリデーションを行い、失敗した場合に None を返すことができます。

class MyClass:
    def __init__(self, value: int):
        if value < 0:
            raise ValueError("value must be non-negative")
        self.value = value
    
    @classmethod
    def create(cls, value: int):
        if value < 0:
            print("Invalid value, returning None")
            return None
        return cls(value)

# 使用例
instance = MyClass.create(-1)  # Invalid value, returning None
print(instance)  # None

2. ファクトリー関数を使う方法

クラス外部にファクトリー関数を用意する方法もあります。この方法では、より柔軟にインスタンス生成ロジックをカプセル化できます。

class MyClass:
    def __init__(self, value: int):
        self.value = value

def create_myclass(value: int) -> MyClass | None:
    if value < 0:
        print("Invalid value, returning None")
        return None
    return MyClass(value)

# 使用例
instance = create_myclass(-1)  # Invalid value, returning None
print(instance)  # None

3. __new__ を使う方法(データベース接続の例外処理)

__new__ メソッドをオーバーライドして、データベース接続時にエラーが発生した場合にインスタンス生成を中止する方法です。このサンプルでは、データベース接続で例外が発生した場合に None を返します。

import sqlite3

class DatabaseConnection:
    def __new__(cls, db_name: str):
        try:
            # データベース接続の試行
            connection = sqlite3.connect(db_name)
        except sqlite3.DatabaseError as e:
            print(f"Database connection failed: {e}")
            return None  # 例外発生時にインスタンス生成を中止
        else:
            # 接続成功時はインスタンスを生成
            instance = super().__new__(cls)
            instance.connection = connection
            return instance
    
    def __init__(self, db_name: str):
        pass  # 初期化処理は不要

    def close(self):
        if hasattr(self, 'connection'):
            self.connection.close()

# 使用例
db_instance = DatabaseConnection("non_existent_db.db")
print(db_instance)  # Database connection failed: unable to open database file / None

Discussion