web-dev-qa-db-ja.com

super()とスーパークラスを直接呼び出すことの違い

Python 2.7および3では、次のメソッドを使用してスーパークラスの関数を呼び出します。

_class C(B):
    def __init__(self):
        B.__init__(self)
_

B.__init__(self)super(B, self).__init__()に置き換えたり、python3ではsuper().__init__()に置き換えたりすることも可能だと思います。

どちらの方法でもこれを行うことの長所または短所はありますか?少なくとも私にとってはBから直接呼び出す方が理にかなっていますが、super()がメタクラスを使用する場合にのみ使用できるのには十分な理由があるかもしれません(私は一般的に避けています)。

31
johannestaas

単一継承の場合、super()は、基本型を参照するためのより洗練された方法です。そうすることで、たとえば基本型の名前を変更する場合などに、コードをより保守しやすくします。どこでもsuperを使用している場合は、class行で変更する必要があります。

ただし、本当の利点は多重継承です。 superを使用する場合、1回の呼び出しで、all基本型のメソッドが(正しい継承順序で)自動的に呼び出されるだけでなく、また、各メソッドが1回だけ呼び出されるようにします。

これにより、基本的に型に diamond プロパティを設定できます。単一の基本型Aと、両方ともBから派生した2つの型CAがあります。そして、DBの両方から継承するタイプCがあります(暗黙的にAからも継承します— 2回)。ここで基本型のメソッドを明示的に呼び出すと、Aのメソッドを2回呼び出すことになります。ただし、superを使用すると、1回だけ呼び出されます。

_class A (object):
    def __init__ (self):
        super().__init__()
        print('A')

class B (A):
    def __init__ (self):
        super().__init__()
        print('B')

class C (A):
    def __init__ (self):
        super().__init__()
        print('C')

class D (C, B):
    def __init__ (self):
        super().__init__()
        print('D')
_

Dをインスタンス化すると、次の出力が得られます。

_>>> D()
A
B
C
D
<__main__.D object at 0x000000000371DD30>
_

それでは、基本型のメソッドを手動で呼び出して、これらすべてをもう一度実行してみましょう。

_class A2 (object):
    def __init__ (self):
        print('A2')

class B2 (A2):
    def __init__ (self):
        A2.__init__(self)
        print('B2')

class C2 (A2):
    def __init__ (self):
        A2.__init__(self)
        print('C2')

class D2 (C2, B2):
    def __init__ (self):
        B2.__init__(self)
        C2.__init__(self)
        print('D2')
_

そしてこれは出力です:

_>>> D2()
A2
B2
A2
C2
D2
<__main__.D2 object at 0x0000000003734E48>
_

ご覧のとおり、_A2_は2回発生します。これは通常あなたが望むものではありません。 superを使用する基本タイプの1つのメソッドを手動で呼び出すと、さらに厄介になります。したがって、代わりに、super()を使用してすべてが機能することを確認する必要があります。また、あまり心配する必要もありません。

52
poke