スーパークラスのメソッドを呼び出す必要がある例はどこにでもあります:
super(SuperClass, instance).method(args)
行うことには欠点がありますか:
SuperClass.method(instance, args)
次の状況を考慮してください。
_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
の___init__
_がスキップされるため、それは悪いことです。その理由は、B
の___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)
の呼び出しと同じthinkかもしれませんが、間違っているだろう。上記の状況では、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__
_ super
が次に呼び出すかもしれないことを知らないため、___init__
_に対して同じ呼び出しシグネチャを持つ必要があります。 _**kwargs
_ を使用します。さらに、super
をどこでも使用することについて一貫している必要があります。 (上記の例のように)一度スキップすると、super
の目的全体が無効になります。その他の落とし穴については、リンクを参照してください。
クラス階層を完全に制御できる場合、または継承ダイアモンドを回避する場合は、super
は不要です。
あなたの例は多少見当違いですが、ペナルティはありません。最初の例では、
super(SubClass, instance).method(args) # Sub, not SuperClass
そして、それは Pythonドキュメント を引用することにつながります:
super
には2つの典型的な使用例があります。単一継承のクラス階層では、super
を使用して、明示的に名前を付けずに親クラスを参照できるため、コードの保守性が向上します。これは、他のプログラミング言語でのsuper
の使用と密接に類似しています。2番目の使用例は、動的な実行環境で協調的な多重継承をサポートすることです。この使用例はPythonに固有であり、静的にコンパイルされた言語や単一の継承のみをサポートする言語には見られません。これにより、複数の基本クラスが同じメソッドを実装する「ダイヤモンドダイアグラム」を実装できます良い設計では、このメソッドはすべてのケースで同じ呼び出しシグネチャを持つことが規定されています(呼び出しの順序は実行時に決定されます。なぜなら、その順序はクラス階層の変更に適応し、その順序には前に未知の兄弟クラスを含めることができるためです)ランタイム)。
基本的に、最初のメソッドを使用することで、単一クラス階層のために親クラスをそこにハードコーディングする必要がなく、複数を使用するときに2番目のメソッドを使用して(効率的/効果的に)本当にあなたが望むことを実際に行うことはできません継承。