3

Python で MRO を理解しようとしています。ここにいろいろ投稿がありますが、特に欲しいものが手に入っているわけではありません。から派生した2 つのクラスAを考えてみましょう。それぞれ異なるパラメータを使用します。BBaseClass__init__

class BaseClass(object):
    def __init__(self):
        print "I am the base class"

class A(BaseClass):
    def __init__(self, something, anotherthing):
        super(A, self).__init__()
        self.something = something
        self.anotherthing = anotherthing
    def methodsA(self):
        ...

class B(BaseClass):
    def __init__(self, someOtherThing):
        super(B, self).__init__()
        self.someOtherThing = someOtherThing 
    def methodsB(self):
        ...

問題は、とのC両方からサード クラスを派生させる必要がある場合、どのように を初期化する必要があるかということです。またはのいずれかから安全に導出できます。AB__init__CBA

   class C(A,B):
     def __init__(self, something, anotherthing, someOtherThing):
         super(C, self).__init__(something, anotherthing, someOtherThing)

上記の実装ではエラーが発生します。

4

5 に答える 5

1

これには使えないと思いますsuper。「古いスタイル」を使用する必要があります。

class C(A,B):
    def __init__(self, something, anotherthing, someOtherThing):
        A.__init__(self, something, anotherthing)
        B.__init__(self, someOtherThing)
于 2014-02-18T18:49:19.270 に答える
0

bj0の答えはほとんど正しいですが、引数を手動で抽出することは、kwargs必要以上に複雑で厄介です。また、追加の引数がクラス コンストラクターの 1 つに渡されても検出されないことも意味します。

最善の解決策は を受け入れること**kwargsですが、未知の引数を渡すためにのみ使用してください。これがobject(BaseClassのベース) に到達すると、不要な引数があるとエラーが発生します。

class BaseClass(object):
    def __init__(self, **kwargs):
        super(BaseClass, self).__init__(**kwargs) # always try to pass on unknown args

class A(BaseClass):
    def __init__(self, something, anotherthing, **kwargs): # take known arguments
        super(A, self).__init__(**kwargs) # pass on the arguments we don't understand
        self.something = something
        self.anotherthing = anotherthing

class B(BaseClass):
    def __init__(self, someOtherThing, **kwargs): # same here
        super(B, self).__init__(**kwargs) # and here
        self.someOtherThing = someOtherThing 

class C(A, B): # this will work, with someOtherThing passed from A.__init__ to B.__init__
    pass

class D(B, A): # this will also work, with B.__init__ passing on A.__init__'s arguments
    pass

import threading
class E(C, threading.Thread): # keyword arguments for Thread.__init__ will work!
    def run(self):
        print(self.something, self.anotherthing, self.someOtherThing)

クラスの 1 つが、その基本クラスの 1 つでも使用されている引数を変更する (またはデフォルトを提供する) 場合、特定のパラメーターを取得して、キーワードで渡すことができます。

class F(C):
    def __init__(self, something, **kwargs):
        super(F, self).__init__(something="foo"+something, **kwargs)

キーワード引数のみを使用してすべてのコンストラクターを呼び出し、位置引数を使用しない必要があります。例えば:

f = F(something="something", anotherthing="bar", someOtherThing="baz")

位置引数に同様のものをサポートすることは可能ですが、引数の順序を当てにできないため、通常は悪い考えです。位置引数を取るクラスが 1 つしかない場合 (おそらく ではそれらの数が不明)、各メソッドに出入り*argsすることでおそらく機能させることができますが、異なる位置引数を取る複数のクラスは順序が原因で問題を引き起こしています。多重継承を行うと、変更される可能性があります。*args__init__

于 2014-02-18T21:25:27.057 に答える
0

これを理解するには、引数なしで試してください。

class BaseClass(object):
    def __init__(self):
        print("BaseClass.__init__")

class A(BaseClass):
    def __init__(self):
        print("A.__init__")
        super(A, self).__init__()

class B(BaseClass):
    def __init__(self):
        print("B.__init__")
        super(B, self).__init__()

class C(A, B):
    def __init__(self):
        print("C.__init__")
        super(C, self).__init__()

これを実行すると:

>>> c = C()
C.__init__
A.__init__
B.__init__
BaseClass.__init__

これが何superをするかです: 重複することなく、正しい順序ですべてが呼び出されるようにします。とCから継承するため、両方のメソッドを呼び出す必要があり、両方とも から継承する必要があるため、これも呼び出す必要がありますが、1 回だけです。AB__init__BaseClass__init__

呼び出される__init__メソッドが異なる引数を取り、追加の引数 ( など*args, **kwargs) を処理できない場合は、TypeError参照する s を取得します。これを修正するには、すべてのメソッドが適切な引数を処理できることを確認する必要があります。

于 2014-02-18T18:42:15.690 に答える
-1

MROを理解するのを手伝ってくれてありがとう。以下は、私の完全なコードと出力です。これが他の人にも役立つことを願っています。

クラス BaseClass(オブジェクト):

    def __init__(self, *args, **kwargs):
        self.name = kwargs.get('name')

    def printName(self):
        print "I am called from BaseClass"
        print self.name

    def setName(self, givenName):
        print "I am called from BaseClass"
        self.name=givenName

    def CalledFromThirdGen(self):
        print "I am called from BaseClass and invoked from Third Generation Derived            Class"

クラス FirstGenDerived(BaseClass):

    def __init__(self, *args, **kwargs):
        super(FirstGenDerived, self).__init__(*args, **kwargs)
        self.name = kwargs.get('name')
        self.FamilyName = kwargs.get('FamilyName')

    def printFullName(self):
        print "I am called from FirstDerivedClass"
        print self.name + ' ' + self.FamilyName

    def printName(self):
        print "I am called from FirstDerivedClass, although I was present in BaseClass"
        print "His Highness " + self.name + ' ' + self.FamilyName

クラス SecondGenDerived(BaseClass):

    def __init__(self, *args, **kwargs):
        super(SecondGenDerived, self).__init__(*args, **kwargs)
        self.name = kwargs.get('name')
        self.middleName = kwargs.get('middleName')
        self.FamilyName = kwargs.get('FamilyName')

    def printWholeName(self):
        print "I am called from SecondDerivedClass"
        print self.name + ' ' + self.middleName + ' ' + self.FamilyName

    def printName(self):
        print "I am called from SecondDerivedClass, although I was present in BaseClass"
        print "Sir " + self.name + ' ' + self.middleName + ' ' + self.FamilyName

class ThirdGenDerived(FirstGenDerived, SecondGenDerived):

    def __init__(self, *args, **kwargs):
        super(ThirdGenDerived, self).__init__(*args, **kwargs)

名前== "メイン" の場合:

    print "Executing BaseClass"
    BaseClass(name='Robin').printName()

    print "Executing Instance of BaseClass with SetName \n"
    Instance = BaseClass()
    Instance.setName("Little John")
    Instance.printName()
    print "################################################\n"


    print "Executing FirstGenDerived with printName and printFullName\n"
    FirstGenDerived(name='Robin', FamilyName='Hood').printFullName()
    FirstGenDerived(name='Robin', FamilyName='Hood').printName()
    print "################################################\n"


    print "Executing FirstGenderived with instance\n"
    Instance2 = FirstGenDerived(name=None, FamilyName="Hood")
    Instance2.setName("Edwards")
    Instance2.printFullName()
    print "################################################\n"

    print "Executing SecondGenDerived with printName and printWholeName\n"
    SecondGenDerived(name='Robin', FamilyName='Hood', middleName='Williams').printWholeName()
    SecondGenDerived(name='Robin', FamilyName='Hood', middleName='Williams').printName()
    print "################################################\n"

    print "Executing ThirdGenDerived\n"
    ThirdGenDerived(name='Robin', FamilyName='Hood', middleName='Williams').CalledFromThirdGen()
    ThirdGenDerived(name='Robin', FamilyName='Hood', middleName='Williams').printName()
    print "################################################\n"

出力: BaseClass の実行 I は BaseClass から呼び出されます Robin Executing Instance of BaseClass with SetName

BaseClass から呼び出されます BaseClass から呼び出されます Little John

printName と printFullName を指定して FirstGenDerived を実行する

私は FirstDerivedClass から呼び出されました Robin Hood 私は FirstDerivedClass から呼び出されましたが、BaseClass には出席していましたが、Robin Hood 殿下

インスタンスを使用して FirstGenbuilt を実行する

BaseClass から呼び出されます FirstDerivedClass から呼び出されます Edwards Hood

printName と printWholeName を指定して SecondGenDerived を実行する

私は SecondDerivedClass から呼び出されました Robin Williams Hood 私は SecondDerivedClass から呼び出されましたが、BaseClass には存在していました ロビン・ウィリアムズ・フッド卿

ThirdGenDerived の実行

私は BaseClass から呼び出され、Third Generation Derived Class から呼び出されます 私は FirstDerivedClass から呼び出されますが、私は BaseClass に存在していました ロビン・フッド殿下

于 2014-02-18T20:33:08.930 に答える