web-dev-qa-db-ja.com

Python多重継承:呼び出すsuper()の選択

Pythonでは、どのParentのメソッドを呼び出すかをどのように選択しますか?親ASDF2の__init__メソッドを呼び出したいとします。 super()でASDF1を指定する必要があるようです。そして、ASDF3の__init__を呼び出したい場合、ASDF2 ?!を指定する必要があります。

>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF1, self).__init__()


>>> ASDF()
ASDF2's __init__ happened
>>> class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        super(ASDF2, self).__init__()


>>> ASDF()
ASDF3's __init__ happened

私にはおかしなようです。私は何を間違えていますか?

42
Name McChange

それは super() の目的ではありません。 Superは基本的に、特定の順序で親の1つ(またはすべて)を選択します。単一の親のメソッドのみを呼び出したい場合は、これを行います

class ASDF(ASDF1, ASDF2, ASDF3):
    def __init__(self):
        ASDF2.__init__(self)
59
Falmarri

superは、メソッド解決順序で次のメソッドを呼び出します。線形継承ツリーでは、直接の親クラスのメソッドになります。

ここには3つの親があり、__init__の観点からの次のASDF1メソッドはASDF2のメソッドです。一般的に、安全なことは、他の何かをしたい理由がわからない限り、継承リストの最初のクラスをsuperに渡すことです。

このすべてのポイントは、どの__init__メソッドを呼び出すかを明示的に選択する必要がないようにすることです。ここでの質問は、すべてのスーパークラス__init__メソッドを呼び出したくない理由です。

Pythonでのsuperの使用に関するかなり多くの文献があります。トピックをGoogleで検索し、どのような結果になるか読むことをお勧めします。

10
Marcin

ASDF1(親クラスの1つ)をsuper()の最初の引数として渡します。それをしないでください。代わりに、super()の最初の引数としてASDFを渡す必要があります。

super()のPython 2.7ドキュメント

Python 2.7ドキュメントを引用すると、典型的なスーパークラスの呼び出しは次のようになります。

class C(B):
    def method(self, arg):
        super(C, self).method(arg)

ここでsuperの最初の引数はCであり、これが現在のクラスであることに注意してください。 B(親クラス)をsuper()に渡さないでください。

メソッド解決順序(MRO)を決定すると、最初の引数として渡されたクラスをスーパースキップし、そのクラスの親と兄弟の検索を開始します。そのため、super()の最初の引数としてASDF1を渡すと、ASDF1をスキップし、ASDF2で検索を開始しました。 ASDF2の__init__ と呼ばれていました。


Python 3では、現在のクラスを渡す必要はありません。

class C(B):
    def method(self, arg):
        super().method(arg)    # This does the same thing as:
                               # super(C, self).method(arg)
                               # (Python 3 only)
3
Christian Long