スーパークラスのメソッドは次のように呼び出す必要があるという例を至る所で見かけます。
super(SuperClass, instance).method(args)
以下のことを行うことで何かデメリットはありますか?
SuperClass.method(instance, args)
ベストアンサー1
次の状況を考えてみましょう。
class A(object):
def __init__(self):
print('Running A.__init__')
super(A,self).__init__()
class B(A):
def __init__(self):
print('Running B.__init__')
# super(B,self).__init__()
A.__init__(self)
class C(A):
def __init__(self):
print('Running C.__init__')
super(C,self).__init__()
class D(B,C):
def __init__(self):
print('Running D.__init__')
super(D,self).__init__()
foo=D()
したがって、クラスはいわゆる継承ダイヤモンドを形成します。
A
/ \
B C
\ /
D
コードを実行すると
Running D.__init__
Running B.__init__
Running A.__init__
C
'sがスキップされるので、これはよくありません__init__
。その理由は、B
's が's を直接__init__
呼び出すためです。A
__init__
の目的はsuper
相続ダイヤモンドを解決することですコメントを外すと
# super(B,self).__init__()
コメントアウト
A.__init__(self)
このコードはより望ましい結果をもたらします:
Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
これですべての__init__
メソッドが呼び出されます。定義時に次のことに注意してくださいB.__init__
。考えるこれsuper(B,self).__init__()
は を呼び出すのと同じですA.__init__(self)
が、それは間違いです。上記の状況では、super(B,self).__init__()
は実際には を呼び出しますC.__init__(self)
。
なんと、B
について何も知らないのにC
、を とsuper(B,self)
呼ぶことを知っているのですか? その理由は、が含まれているからです。言い換えると、(または上記の) は について知っています。C
__init__
self.__class__.mro()
C
self
foo
C
したがって、注意してください。この 2 つは代替可能ではありません。結果が大きく異なる可能性があります。
使用super
落とし穴があります。継承図のすべてのクラス間では、かなりのレベルの調整が必要です。(たとえば、 の呼び出しシグネチャが同じである必要があります__init__
。そうしないと、どのクラスが次に__init__
どのクラスを呼び出すかわかりません__init__
super
。そうでなければ、使用**kwargs
) さらに、super
どこでも の使用に一貫性を持たせる必要があります。 を 1 回でも省略すると (上記の例のように)、 の目的が完全に達成されなくなりますsuper
。 その他の落とし穴については、リンクを参照してください。
クラス階層を完全に制御している場合、または継承ダイヤモンドを回避している場合は、 は必要ありませんsuper
。