__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__が呼び出されていることを確認するために記述しています。