web-dev-qa-db-ja.com

このプロパティが派生クラスで上書きされている場合、基本クラスのプロパティを呼び出す方法は?

私は、いくつかのクラスをゲッターとセッターの広範囲な使用から、よりPython的なプロパティの使用に変更しています。

しかし、今では、以前のgetterまたはsetterのいくつかが基本クラスの対応するメソッドを呼び出してから、他の何かを実行するために立ち往生しています。しかし、プロパティでこれをどのように達成できますか?親クラスでプロパティのゲッターまたはセッターを呼び出す方法は?

もちろん、属性自体を呼び出すだけで、無限の再帰が得られます。

class Foo(object):

    @property
    def bar(self):
        return 5

    @bar.setter
    def bar(self, a):
        print a

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return self.bar # --> recursion!

    @bar.setter
    def bar(self, c):
        # perform the same action
        # as in the base class
        self.bar = c    # --> recursion!
        # then do something else
        print 'something else'

fb = FooBar()
fb.bar = 7
79
UncleZeiv

プロパティによって呼び出される基本クラス関数を呼び出すことができると思うかもしれません:

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar(self)

これは試してみるのが最も明らかなことですが、-バーは呼び出し可能ではなくプロパティであるため機能しません。

しかし、プロパティは単なるオブジェクトであり、対応する属性を見つけるゲッターメソッドがあります。

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar.fget(self)
90

スーパー トリックを行う必要があります:

return super().bar

Python 2.xでは、より冗長な構文を使用する必要があります。

return super(FooBar, self).bar
44
Pankrat

基本クラス名を明示的に参照する必要のないsuperを使用する代替方法があります。

基本クラスA:

class A(object):
    def __init__(self):
        self._prop = None

    @property
    def prop(self):
        return self._prop

    @prop.setter
    def prop(self, value):
        self._prop = value

class B(A):
    # we want to extend prop here
    pass

Bでは、親クラスAのプロパティゲッターにアクセスします。

他の人がすでに答えているように、それは次のとおりです。

super(B, self).prop

またはPython 3:

super().prop

これは、ゲッター自体ではなく、プロパティのゲッターによって返される値を返しますが、ゲッターを拡張するには十分です。

Bでは、親クラスAのプロパティセッターにアクセスします。

私がこれまでに見た中で最高の推奨事項は次のとおりです。

A.prop.fset(self, value)

私はこれが優れていると信じています:

super(B, self.__class__).prop.fset(self, value)

この例では、両方のオプションは同等ですが、superを使用すると、Bの基本クラスから独立しているという利点があります。 Bがプロパティを拡張するCクラスから継承する場合、Bのコードを更新する必要はありません。

Aのプロパティを拡張するBの完全なコード:

class B(A):
    @property
    def prop(self):
        value = super(B, self).prop
        # do something with / modify value here
        return value

    @prop.setter
    def prop(self, value):
        # do something with / modify value here
        super(B, self.__class__).prop.fset(self, value)

1つの注意点:

プロパティにセッターがない場合は、セッターとゲッターの両方の動作を変更する場合でも、それらの両方をBで定義する必要があります。

18
Maxime R.

試してみる

@property
def bar:
    return super(FooBar, self).bar

pythonが基本クラスプロパティの呼び出しをサポートしているかどうかはわかりませんが、プロパティは実際には指定された関数で設定され、クラス内のその名前を置き換える呼び出し可能なオブジェクトです。簡単に利用可能なスーパー機能がないことを意味します。

ただし、property()関数を使用するように構文をいつでも切り替えることができます。

class Foo(object):

    def _getbar(self):
        return 5

    def _setbar(self, a):
        print a

    bar = property(_getbar, _setbar)

class FooBar(Foo):

    def _getbar(self):
        # return the same value
        # as in the base class
        return super(FooBar, self)._getbar()

    def bar(self, c):
        super(FooBar, self)._setbar(c)
        print "Something else"

    bar = property(_getbar, _setbar)

fb = FooBar()
fb.bar = 7
4
workmad3