Contents
__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() print(obj) # None
__new__()メソッドが呼び出されていますが、インスタンスを返していないため、オブジェクトが生成されず、__init__()メソッドが呼び出されていない点に注目してください。ま、__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__') def __str__(self): return "***** " + super().__str__() obj = MyStr("my_str") print(obj)
イミュータブルなクラスstrを継承したクラスを記述していますが、__new__で親クラスのインスタンスを生成したものを返しています。(本来、上記サンプルで__init__は不要なのですが、__new__の後に__init__が呼び出されていることを確認するために記述しています。)