次のコードは機能します。
class Foo(Tuple):
def __init__(self, b):
super(Foo, self).__init__(Tuple(b))
if __== '__main__':
print Foo([3, 4])
$ python play.py
結果:
play.py:4: DeprecationWarning: object.__init__() takes no parameters
super(Foo, self).__init__(Tuple(b))
(3, 4)
しかし、次のことではありません
class Foo(Tuple):
def __init__(self, a, b):
super(Foo, self).__init__(Tuple(b))
if __== '__main__':
print Foo(None, [3, 4])
$ python play.py
結果:
Traceback (most recent call last):
File "play.py", line 7, in <module>
print Foo(None, [3, 4])
TypeError: Tuple() takes at most 1 argument (2 given)
どうして?
タプルは不変なので、代わりに___new__
_をオーバーライドする必要があります。
object.__new__(cls[, ...])
クラス
cls
の新しいインスタンスを作成するために呼び出されます。__new__()
は、インスタンスが要求されたクラスを最初の引数として受け取る静的メソッド(特別なケースであるため、宣言する必要はありません)です。残りの引数は、オブジェクトコンストラクタ式に渡される引数(クラスの呼び出し)です。__new__()
の戻り値は、新しいオブジェクトインスタンス(通常はcls
のインスタンス)である必要があります。通常の実装では、適切な引数を指定して
__new__()
を使用し、スーパークラスのsuper(currentclass, cls).__new__(cls[, ...])
メソッドを呼び出し、必要に応じて新しく作成されたインスタンスを変更してから返すことにより、クラスの新しいインスタンスを作成します。
__new__()
がcls
のインスタンスを返す場合、新しいインスタンスの__init__()
メソッドは__init__(self[, ...])
のように呼び出されます。ここで、selfは新しいインスタンスであり、残りの引数は、__new__()
に渡されたものと同じです。
__new__()
がcls
のインスタンスを返さない場合、新しいインスタンスの__init__()
メソッドは呼び出されません。
__new__()
は、主に不変タイプのサブクラス(int
、str
、Tuple
など)がインスタンスの作成をカスタマイズできるようにすることを目的としています。また、クラスの作成をカスタマイズするために、カスタムメタクラスで一般的にオーバーライドされます。
タプル値を割り当てるには、__new__
メソッドをオーバーライドする必要があります。
class Foo(Tuple):
def __new__ (cls, a, b):
return super(Foo, cls).__new__(cls, Tuple(b))
引数は、Tupleクラスの__init__
実装では無視されているようですが、初期化を行う必要がある場合は、次のように実行できます。
class Foo(Tuple):
def __new__ (cls, a, b):
return super(Foo, cls).__new__(cls, Tuple(b))
def __init__(self, a, b):
self.a=a
self.b=b
if __== '__main__':
foo = Foo(None, [3, 4])
print foo
print foo.a
print foo.b