インスタンスアロケータ

__new__()メソッド

クラス定義に__new__()メソッドがあれば、インスタンス生成時に「インスタンスを生成するために」呼びだされます。

__new__()メソッドの第1引数は、clsを指定しますが、これはインスタンスではなく、クラスオブジェクトです。

また、戻り値にそのクラスのインスタンスを指定した場合、そのインスタンスの___init__メソッドが呼びだされます。

サンプルで動作を確認してみましょう。

class MyClass:
    def __new__(cls):
        print('__new__')
        print(cls)
        
    def __init__(self):
        print('__init__')
        
    def __str__(self):
        return 'test'

obj = MyClass()

実行結果

__new__
<class '__main__.MyClass'>

__new__()メソッドが呼び出されて__init__()メソッドが呼び出されていない点に注目してください。
また、__new__()メソッドの引数は、クラスオブジェクトであることが解ると思います。

戻り値にオブジェクトを指定した場合は次に説明します。

イミュータブルクラスの継承と__new__

通常のクラスの場合、__new__を実装する必要はありません。では、どういった場合に__new__を実装する必要が出てくるのでしょうか?

使いどころの1つとして、イミュータブルなクラスを継承したクラスの場合が挙げられます。

イミュータブルなクラスを継承した場合、以下のような記述ができません。

class MyClass(イミュータブルクラス):
    def __init__(self, value):
        self.value = value

なぜならば、前述の通り、__init__処理の時点で既にインスタンスが生成されているため、selfを書き換えることはできないのです。

このため、この場合以下のように__new__を利用することでこの問題を回避することができます。

class MyStr(str):

    def __new__(cls, text):
        print('__new__')
        return super().__new__(cls, text)

    def __init__(self, text):
       print('__init__')

obj = MyStr("my_str")
print(obj)

本来、上記サンプルで__init__は不要なのですが、__new__の後に__init__が呼び出されていることを確認するために記述しています。