web-dev-qa-db-ja.com

異なるシグネチャを持つpython3の多重継承

ABCの3つのクラスがあります。

Cは、AおよびBを(この順序で)継承します。 ABのコンストラクターシグネチャは異なります。両方の親クラスの__init__メソッドを呼び出すにはどうすればよいですか?

コードでの私の努力:

class A(object):
    def __init__(self, a, b):
        super(A, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        super(B, self).__init__()
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super(A, self).__init__(1, 2)
        super(B, self).__init__(3)

c = C()

エラーが発生します:

Traceback (most recent call last):
  File "test.py", line 16, in <module>
    c = C()
  File "test.py", line 13, in __init__
    super(A, self).__init__(1, 2)
TypeError: __init__() takes 2 positional arguments but 3 were given

このリソース を見つけました。これは、異なる引数セットを持つ複数の継承を説明していますが、すべての引数に*argsおよび**kwargsを使用することを推奨します。子クラスのコンストラクター呼び出しから、どのようなパラメーターを親クラスに渡すのかわからないので、これは非常にいものです。

41

notは、何をしているのかわからない限りsuper(baseclass, ...)を使用してください。 super()の最初の引数は、使用する次のメソッドを探すときにskipにどのクラスを指定するかを伝えます。例えば。 super(A, ...)はMROを調べ、Aを見つけ、nextベースクラス、not__init__を探し始めます。 A自体。 Cの場合、MROは(C, A, B, object)であるため、super(A, self).__init__B.__init__を検出します。

これらの場合、協調的継承を使用したくないが、代わりに直接A.__init__B.__init__を参照します。 super()は、呼び出すメソッドに同じ署名があるか、サポートされていない引数を*args**vargsで飲み込む場合にのみ使用してください。その場合、1つのsuper(C, self).__init__()呼び出しだけが必要になり、MRO順序の次のクラスが呼び出しの連鎖を処理します。

別の言い方をすれば、super()を使用すると、MROの次のクラスがわからないため、クラスが渡す引数をより適切にサポートします。そうでない場合は、notsuper()を使用します。

ベースの__init__メソッドを直接呼び出す:

class A(object):
    def __init__(self, a, b):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q):
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        # Unbound functions, so pass in self explicitly
        A.__init__(self, 1, 2)
        B.__init__(self, 3)

協調的なsuper()の使用:

class A(object):
    def __init__(self, a=None, b=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))

class B(object):
    def __init__(self, q=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))

class C(A, B):
    def __init__(self):
        super().__init__(a=1, b=2, q=3)
77
Martijn Pieters