2

私はひし形の継承という奇妙な状況に陥っています。さらに悪いことに、ひし形の真ん中にあるクラスがメンバーを共有しています。以下に、私の問題を強調するコードの切り詰めを示しました。

組み込み関数の python ドキュメント サイトにリンクされているhttp://rhettinger.wordpress.com/2011/05/26/super-considered-super/から学んだクラスの作成に使用した方法super

class A(object):
    pass

class B(A):
    def __init__(self, z=None, **kwargs):
        self.z = z
        super(B, self).__init__(**kwargs)
        # super(B, self).__init__(z=z, **kwargs)

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

class D(B, C):
    pass

d = D(z='y')

for arg, value in d.__dict__.iteritems():
    print arg, ':', value

出力を与える

z : None

問題は、キーワード引数を使用して関数のシグネチャが一致することを確認する方法が、クラス C の init 呼び出しから z 引数を奪うことです。引数を kwargs に強制的に追加することはできますが (コメント付きのコードを参照)、これにより、型 B のオブジェクトをインスタンス化できなくなります。これは、パラメーターを取らないオブジェクトの init への呼び出しになるためです。以下のオブジェクトのいずれかをインスタンス化するときに無効な引数を入れるのを防ぐため、素晴らしい機能です。

また、変数を設定する前にスーパー行があると、最高レベルのオブジェクトが下位レベルを上書きするため、問題が修正されることに気付きました。ただし、実際のすべての「設定」は下位レベルのクラスによって実行され、上位レベルのクラスは継承のチェーンに設定される値を渡すため、私のコードは最後にスーパーを中心に構築されています。親の呼び出しのどこに収まるかについてのガイドラインはありますか?

何かアイデアはありますか?

ありがとう

ps これは「共同クラス」の設計が悪いだけですか? 協力クラスとは正確には何ですか?従うべき規則やガイドラインはありますか?

編集:

Stackoverflow では自分の質問に答えることはできませんが、解決策を思いつきました。

協同クラス間で共有メンバーが存在するべきではないと思います。メンバーを共有する、互いに独立している 2 つのクラスが存在する場合 (「ある種類」の関係がないという意味で)、継承関係に抽象化のレベルを追加する必要があります。

共有メンバーを取り出して、共有基本クラスから継承し、ひし形のクラスによって継承される別のクラスに配置する必要があります。

以下、修正したコードです。OPのリンクに合わせて、ルート基本クラスを導入しました

私は正式なプログラミング教育を受けていないことを指摘する必要があります (ここで私が推測するほとんどのように) ので、間違った用語を使用した場合は申し訳ありません.

class Root(object):
    pass

class A(Root):
    pass

class HasAZ(Root):
    def __init__(self, z=None, **kwargs):
        self.z = z
        super(HasAZ, self).__init__(**kwargs)

class B(HasAZ, A):
    pass


class C(HasAZ, A):
    pass

class D(B, C):
    pass

d = D(z='y')

for arg, value in d.__dict__.iteritems():
    print arg, ':', value
4

2 に答える 2

1

これは単に「協同クラス」の設計が悪いのでしょうか?

はい、特に属性の衝突のためです。属性が同じ名前でなければ、これまでのところ問題にはB.zなりませんC.z

協力クラスとは正確には何ですか?従うべき規則やガイドラインはありますか?

あなたがすでに読んだもの:

http://rhettinger.wordpress.com/2011/05/26/super-considered-super/

私が知る限り、これが協同組合のルール/ガイドラインの最良の情報源です。

あなたには選択の余地があります。あなたはできる:

  • 継承ツリー内のすべてのクラスで属性名を一意にする

また

  • 常にすべての引数をツリーの下に渡します。その時点で、すべての署名を次のように変更することもできます__init__(self, **kwargs)

また

  • 多重継承を使わない
于 2012-02-22T22:53:41.683 に答える
1

もっと良い方法があるかもしれませんが、これは上書きを避けるべきです::

class C(A):
    def __init__(self, z=None, **kwargs):
        if not hasattr(self, 'z'):
            self.z = z
        super(C, self).__init__(**kwargs)
于 2012-02-22T21:57:53.077 に答える