スーパークラスメソッドを呼び出す必要がある例はどこにでもあります。
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
'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
super
クラス階層を完全に制御できる場合、または継承ダイアモンドを回避する場合は、の必要はありませんsuper
。
あなたの例は多少間違っていますが、そのままではペナルティはありません。最初の例では、
super(SubClass, instance).method(args) # Sub, not SuperClass
そして、それはPythonのドキュメントを引用することにつながります:
には 2 つの典型的な使用例があり
super
ます。単一継承のクラス階層では、super
明示的に名前を付けずに親クラスを参照するために使用できるため、コードがより保守しやすくなります。この使用法はsuper
、他のプログラミング言語での の使用法とよく似ています。2 番目の使用例は、動的な実行環境で協調多重継承をサポートすることです。この使用例は Python に固有のものであり、静的にコンパイルされた言語や単一継承のみをサポートする言語には見られません。これにより、複数の基本クラスが同じメソッドを実装する「ダイヤモンド ダイアグラム」を実装できます。優れた設計では、このメソッドがすべての場合に同じ呼び出しシグネチャを持つように指示されます (呼び出しの順序は実行時に決定され、その順序はクラス階層の変更に適応し、その順序には実行前に不明な兄弟クラスが含まれる可能性があるため) )。
基本的に、最初の方法を使用することで、単一クラスの階層のためにそこに親クラスをハードコーディングする必要はありません。継承。