言いたいこと
super(A, self)
ではなくsuper()
と書いた方が良い。
経緯
諸事情により、Aという名前のクラスを、同一モジュール内で2回以上宣言しなければならないとします。
大まかにはこういうコードが書かれます。
fool1.py
class A:
pass
a11 = A()
a12 = A()
class A:
pass
a21 = A()
a22 = A()
クラス定義というのは、言い換えれば(type
による)クラスオブジェクトの生成ですから、2つのAクラスは別オブジェクトです。
当然、こうなります。
>>> a11.__class__ is a12.__class__
True
>>> a21.__class__ is a22.__class__
True
>>> a11.__class__ is a21.__class__
False
>>> a12.__class__ is a22.__class__
False
このことを意識せずにsuper(A, self)
を使って予想外の動きをするのに悩まされました。
例えば、次のような定義を考えます。
class Asuper:
pass
class A(Asuper):
def get_super1(self):
return super(A, self)
def get_super2(self):
return super()
def get_super3(self):
return super(self.__class__, self)
Aをインスタンス化してget_super[123] を呼び出すと以下のようになります。
>>> a = A()
>>> a.get_super1()
<super: <class 'A'>, <A object>>
>>> a.get_super2()
<super: <class 'A'>, <A object>>
>>> a.get_super3()
<super: <class 'A'>, <A object>>
次に、Aを1回インスタンス化した後にAを再定義してから同じことをやってみます。
>>> a = A()
>>> class A:
... pass
...
>>> a.get_super1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in get_super1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> a.get_super2()
<super: <class 'A'>, <A object>>
>>> a.get_super3()
<super: <class 'A'>, <A object>>
super(A, self)
を使っているget_super1だけTypeError
が発生しました。おそらく、実行中のモジュールにおけるA
という名前が参照するオブジェクトが切り替わったことにより制約違反が発生しました。
これを回避するには、get_super3のように、オブジェクトが参照するクラスオブジェクトを指定すると良いと思います。未確認ですがsuper
の引数を省略するとこのような挙動になってるのではないかと思います。