web-dev-qa-db-ja.com

pythonでプロパティをオーバーライドする

だから、私はPythonでプロパティの特定の関数(たとえば、ゲッター、セッターなど)をオーバーライドできるようにするための最良の(最小限のコードで最もエレガントな)方法を見つけようとしています。私は、すべてのメソッドが同じインデントされたコードのブロックにカプセル化されているという事実のために、次のプロパティの実行方法が好きです(1つのプロパティを処理する関数が停止し、次に開始):

_@apply
def foo():
    """A foobar"""
    def fget(self):
        return self._foo
    def fset(self, val):
        self._foo = val
    return property(**locals())
_

ただし、この方法でプロパティを定義するクラスから継承し、たとえばfoo setter関数をオーバーライドする場合、注意が必要です。私はいくつかの検索を行いましたが、見つかった答えのほとんどは、基本クラスで個別の関数を定義することでした(たとえば、getFoosetFoo)、それらから明示的にプロパティ定義を作成します(例:foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo()))、必要に応じてgetFoosetFoo、およびdelFooをオーバーライドします。

このソリューションが嫌いなのは、プロパティごとにlambasを定義してから、各関数呼び出しを書き出す必要があるからです(property(**locals())を実行する直前の場合)。また、元々持っていたカプセル化も得られません。

理想的には、私ができることは次のようなものです。

_class A(object):
    def __init__(self):
        self.foo = 8
    @apply
    def foo():
        """A foobar"""
        def fget(self):
            return self._foo
        def fset(self, val):
            self._foo = val
        return property(**locals())

class ATimesTwo(A):
    @some_decorator
    def foo():
        def fset(self, val):
            self._foo = val * 2
        return something
_

そして、出力は次のようになります。

_>>> a = A()
>>> a.foo
8
>>> b = ATimesTwo()
>>> b.foo
16
_

基本的に、ATimesTwoAからgetter関数を継承しますが、setter関数をオーバーライドします。誰かがこれを行う方法を知っていますか(上記の例に似た方法で)? _some_decorator_はどの関数になり、foo関数は何を返す必要がありますか?

41
Jessica Hamrick

これは聞いたことがあると思いますが、applyは8年の間廃止されました。Python 2.3。 locals()の使用は、Python-明示的は暗黙的よりも優れています。インデントの増加が本当に好きなら、スローアウェイオブジェクトを作成する必要はありません

_if True:
    @property
    def foo(self):
        return self._foo
    @foo.setter
    def foo(self, val):
        self._foo = val
_

localsを乱用しない、applyを使用する、余分なオブジェクトを作成する必要がある、またはfoo = foo()で後から行を必要とせず、ブロックの終わりを見にくくする。 propertyを使用する従来の方法でも同様に機能します。通常どおりfoo = property(fget, fset)を実行します。

任意のサブクラスのプロパティをオーバーライドする場合は、 このようなレシピ を使用できます。

サブクラスがプロパティが定義された場所を知っている場合、次のようにします。

_class ATimesTwo(A):
    @A.foo.setter
    def foo(self, val):
        self._foo = val * 2
_
46
agf

propertyデコレータのPython docs は、次のイディオムを示唆しています。

class C(object):
    def __init__(self):
        self._x = None
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x

そして、サブクラスは次のように単一のセッター/ゲッターをオーバーライドできます。

class C2(C):
    @C.x.getter
    def x(self):
        return self._x * -1

複数のメソッドをオーバーライドするには、次のようなことを行う必要があるため、これは少し厄介です。

class C3(C):
    @C.x.getter
    def x(self):
        return self._x * -1
    # C3 now has an x property with a modified getter
    # so modify its setter rather than C.x's setter.
    @x.setter 
    def x(self, value):
        self._x = value * 2

もちろん、getter、setter、deleterをオーバーライドする時点で、おそらくC3のプロパティを再定義できます。

51
stderr