1

Python 2.7 では、特定のクラスEからルートへのAN 継承チェーンを再構築しようとしていAます。以下に示すようにダイヤモンドの継承の問題がありますが、THE パスではなくパスに興味があるので、うまくいくはずです。自分が(こうして)や​​るべきことなのかは疑問ですが、今は自分が何を誤解しているのかを知りたいだけです...

class A(object):
    @classmethod
    def supah(thisCls):
        return [cls for cls in thisCls.__bases__ if issubclass(cls, A)]
    def name(self):
        return 'A'

class C(A):
    def name(self):
        return 'C'

class D(A):
    def name(self):
        return 'D'

class E(C, D):
    def name(self):
        return 'E'

current = E
while True:
    try:
        print current, super(current, E()), super(current, E()).name()
    except AttributeError:
        break
    current = current.supah()[0]

出力

<class '__main__.E'> <super: <class 'E'>, <E object>> C
<class '__main__.C'> <super: <class 'C'>, <E object>> D
<class '__main__.A'> <super: <class 'A'>, <E object>>

Dはそこで何をしているの?呼んでいる

super(C, E()).name()

「クラスA」はどこにあるsuper(C, E())べきですか?最初の行の C が DI だったら (ある程度) 理解できたでしょうが、私の考えでは、2 行目は間違いなく A である必要があります。

何か助けはありますか?

編集:私の理解はその呼び出しでした

super(C, obj).name()

C の線形化は であるため、"A" という名前になり[C, A, object]ます。

しかし、これはsuper(C, obj).name()明らかに意味するものではありません。それはまだobjの完全な線形化を使用しています: [E, C, D, A, object](@Martijn Pietersのおかげで)、それはちょうど(後) Cで始まります.したがって、DはAの前に来ます.

4

2 に答える 2

0

@Martijn Pieters による回答は、観測された結果がどのように生成されるかを説明しています。

スーパーから誤って期待していた結果を生成したい場合は、Python で @Sven Marnach から受け入れられた回答に基づいたアプローチを使用できます。指定されたクラスで MRO 検索を開始する super() のようなプロキシ オブジェクト

Aインスタンスのクラスバージョンとして振る舞うものを取得したいC場合:

class Delegate:
    def __init__(self, cls, obj):
        self._delegate_cls = cls
        self._delegate_obj = obj
    def __getattr__(self, name):
        x = getattr(self._delegate_cls, name)
        if hasattr(x, "__get__"):
            return x.__get__(self._delegate_obj)
        return x

次のように取得.name()するために使用できます。A

class C(A):
    def name(self):
        return delegate(A, self).name() + 'C'
C().name()
# result: AC

(最初の) 直接の祖先を取得する超類似構造に興味がある場合:

class parent:
    def __init__(self, cls, obj):
        if len(cls.__bases__):
            self._delegate_cls = cls.__bases__[0]
        else:
            raise Exception('parent called for class "%s", which has no base classes')
        self._delegate_obj = obj
    def __getattr__(self, name):
        x = getattr(self._delegate_cls, name)
        if hasattr(x, '__get__'):
            return x.__get__(self._delegate_obj)
        return x

次のように呼び出されます:

class C(A):
    def name(self):
        return parent(C, self).name() + 'C'
print C().name()
# result: AC

super(py2のように)現在のクラスの名前を明示的に含めない方法はないと思います。

これは特殊な場合のためであることに注意してください。たとえば、私の例では、C実装されていない場合は.name()on A、 neverを呼び出しますD。ただし、クラスからルートへの (「the」ではない) 直接の祖先行を取得できます。また、parent(Cls, obj)は常に の親でありobj、何も知らなかったクラスではなく、Clsたまたま の祖先になりobjます。

于 2014-03-05T19:45:33.740 に答える