15

組み込み型および他のクラスから派生する場合、組み込み型のコンストラクターがスーパークラス コンストラクターを呼び出していないようです。これにより、MRO のビルトインの後にある型に対して __init__ メソッドが呼び出されなくなります。

例:

class A:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print("A().__init__()")

class B(list, A):
    def __init__(self, *args, **kwargs):
        print("B().__init__() start")
        super().__init__(*args, **kwargs)
        print("B().__init__() end")

if __name__ == '__main__':
    b = B()

このサンプルでは、​​ A.__init__ は呼び出されません。代わりにB が定義されている場合class B(A, list)(継承順序を切り替える場合)、意図したとおりに動作します (つまり、 A.__init__ が呼び出されます)。

継承順序へのこの非常に微妙な依存は、かなり非 Pythonic のように見えますが、このように意図されていますか? また、複雑なクラス階層の組み込み型から派生させてはならないということも意味します。なぜなら、他の誰かがクラスから派生したときに組み込み型が MRO のどこに行き着くのかを知ることができないからです (メンテナンスの恐怖)。何か不足していますか?

追加情報: Python バージョン 3.1

4

1 に答える 1

10

の正しい使用法super()はやや微妙であり、共同作業するメソッドのすべてが同じシグネチャを持っていない場合は注意が必要です。__init__()メソッドの通常のパターンは次のとおりです。

class A(object):
    def __init__(self, param_a, **kwargs):
        self.param_a = param_a
        super(A, self).__init__(**kwargs)

class B(A):
    def __init__(self, param_b, **kwargs):
        self.param_b = param_b
        super(B, self).__init__(**kwargs)

class C(A):
    def __init__(self, param_c, **kwargs):
        self.param_c = param_c
        super(C, self).__init__(**kwargs)

class D(B, C):
    def __init__(self, param_d, **kwargs):
        self.param_d = param_d
        super(D, self).__init__(**kwargs)

d = D(param_a=1, param_b=2, param_c=3, param_d=4)

これには、すべてのメソッドが連携する必要があり、メソッドが呼び出される時点が問題にならないように、すべてのメソッドがある程度互換性のある署名を必要とすることに注意してください。

組み込み型のコンストラクターには、このようなコラボレーションに参加できるコンストラクター シグネチャがありません。彼らがこれを呼び出したとしても、super().__init__()すべてのコンストラクター シグネチャが統一されていない限り、かなり役に立たないでしょう。したがって、最終的にはあなたが正しいです。それらは、共同コンストラクター呼び出しへの参加には適していません。

super()すべての共同メソッドが同じ署名 (例: など__setattr__()) を持っている場合、または上記の (または類似の) パターンを使用している場合にのみ使用できます。ただし、基底クラスのメソッドを呼び出すパターンはusingsuper()だけではありません。多重継承パターンに「ひし形」がない場合は、明示的な基本クラス呼び出しを使用できますB.__init__(self, param_a)。複数の基本クラスを持つクラスは、単純に複数のコンストラクターを呼び出します。__init__()ひし形があっても、 anが何回呼び出されても害がないことに注意する限り、明示的な呼び出しを使用できる場合があります。

とにかくコンストラクターに使用したい場合はsuper()、組み込み型のサブクラス ( を除くobject) を複数の継承階層で使用しないでください。さらに読む:

于 2012-01-18T18:42:07.007 に答える