基本的な比較
| __new__ | __init__ |
|---|---|
| インスタンスの生成 | インスタンスの初期化 |
| インスタンス生成時に必ず呼ばれる |
__new__次第で呼ばれないこともある |
| 第一引数clsにクラスオブジェクトが格納される | 第一引数selfにインスタンスオブジェクトが格納される |
Python のすべてのクラスは最終的にobjectクラスを継承しています。
したがって、__new__ や __init__ を自分で定義しない場合は、
objectクラスが持つデフォルトの実装が使われます。
-
object.__new__(cls)
→ クラスclsの新しいインスタンスを生成して返す(インスタンス生成を担当)。 -
object.__init__(self)
→ 受け取ったインスタンスを初期化する(ただしobjectの実装は何もしない)。
インスタンス生成に条件を付けたいとき等や、初期化処理をカスタマイズしたい時に、明示的にこれらを定義して使用します。
__new__の使いどころ
イミュータブル(不変)オブジェクトの初期化
イミュータブルなオブジェクトは、インスタンス生成後には初期化ができないので、生成前に初期化する必要があります。
class DoubleTuple(tuple):
def __new__(cls, iterable):
# 中身を2倍にした新しいタプルを生成
doubled = [x * 2 for x in iterable]
# tuple.__new__ に加工済みのデータを渡して作成
return super().__new__(cls, doubled)
# 使用例
t = DoubleTuple([1, 2, 3])
print(t) # → (2, 4, 6)
Singletonパターン
__new__では、インスタンス生成前に、インスタンス生成における条件を付けることができます。
その性質を使って、「すでにインスタンスが存在している場合は、新しいインスタンスを生成せず既存のインスタンスを返す」という条件を付けてインスタンス生成を行うことができます。
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
__init__の使いどころ
属性に値を設定して初期化する
一番基本的な使い方です。
ほとんどの場合、インスタンス変数を初期化する際に使います。
この時、入力値のチェックをすることもできます。
class People:
def __init__(self, name, age):
if age < 0:
raise ValueError("年齢には正の値を入力してください。")
self.name = name
self.age = age
def greet(self):
print(f"僕は{self.name}です。{self.age}歳です。")
bob = People("Bob", -1) # エラー(ValueError: 年齢には正の値を入力してください。)
tom = People("Tom", 20)
tom.greet() # 僕はTomです。20歳です。
依存オブジェクトや設定の準備
初期化時に必要な外部リソースや他クラスとの関連付けを行います。
インスタンスを使える状態にするためのセットアップに利用できます。
class DatabaseClient:
def __init__(self, conn_str):
self.conn = self.connect_to_db(conn_str)
def connect_to_db(self, conn_str):
# DB接続処理
return f"Connected to {conn_str}"
参考にしたもの