3

@propertyPythonをセッターとゲッターとして同時に機能させる方法はありますか?

これは以前どこかで見たような気がしますが、思い出せず、自分で解決策を再現することもできません。

たとえば、次の代わりに:

class A(object):
  def __init__(self, b): self.b = b
  def get_c(self): return self.b.c
  def set_c(self, value): self.b.c = value
  c = property(get_c, set_c)

Aオブジェクトの場合、属性はgetter、setter (および必要に応じて削除) とc実際に同等であることを何らかの方法で通知できます。b.c

動機:

これは、オブジェクト (インスタンスである)Aのプロキシ ラッパーである必要があるが、データ属性のみを共有し、メソッドを共有しない場合に特に役立ちます。これらのようなプロパティを使用すると、とオブジェクトのデータを完全に同期させたまま、両方を同じコードで使用できます。BbAB

4

5 に答える 5

4

ActiveState に投稿されているこの forwardTo クラスを探していると思います。

このレシピを使用すると、属性アクセスをクラス内の別のオブジェクトに透過的に転送できます。このようにして、クラス インスタンスの一部のメンバーから機能を直接公開できます。たとえば、foo.bar.baz() の代わりに foo.baz() を使用できます。

class forwardTo(object):
    """
    A descriptor based recipe that makes it possible to write shorthands
    that forward attribute access from one object onto another.

    >>> class C(object):
    ...     def __init__(self):
    ...         class CC(object):
    ...             def xx(self, extra):
    ...                 return 100 + extra
    ...             foo = 42
    ...         self.cc = CC()
    ...
    ...     localcc = forwardTo('cc', 'xx')
    ...     localfoo = forwardTo('cc', 'foo')
    ...
    >>> print C().localcc(10)
    110
    >>> print C().localfoo
    42

    Arguments: objectName - name of the attribute containing the second object.
               attrName - name of the attribute in the second object.
    Returns:   An object that will forward any calls as described above.
    """
    def __init__(self, objectName, attrName):
        self.objectName = objectName
        self.attrName = attrName
    def __get__(self, instance, owner=None):
        return getattr(getattr(instance, self.objectName), self.attrName)
    def __set__(self, instance, value):
        setattr(getattr(instance, self.objectName), self.attrName, value)
    def __delete__(self, instance):
        delattr(getattr(instance, self.objectName), self.attrName)

より堅牢なコードについては、 に置き換えることを検討getattr(instance, self.objectName)してoperator.attrgetter(self.objectName)(instance)ください。これによりobjectName、ドット付きの名前を使用できます (たとえば、A.cのプロキシになることができますA.x.y.z.d)。

于 2013-01-07T04:55:56.747 に答える
4

多数のプロパティを A オブジェクトからそのメンバーにデリゲートしようとしている場合は、 、、およびのb中でそれを行う方がおそらく簡単です。__getattr____setattr____delattr__

class A(object):
    delegated = ['c', 'd', 'e', 'f']
    def __getattr__(self, attr):
        if attr in A.delegated:
            return getattr(self.b, attr)
        raise AttributeError()

簡潔にするため、およびと の違いを説明する必要がないように、ここでは__setattr__との定義を示していません。さらに情報が必要な場合は、ドキュメントを参照してください。__delattr____getattr____getattribute__

これは、さまざまな属性をさまざまなメンバーにプロキシしたいクラスに容易に拡張できます。

class A(object):
    b_delegated = ['c', 'd', 'e', 'f']
    x_delegated = ['y', 'z']
    def __getattr__(self, attr):
        if attr in A.b_delegated:
            return getattr(self.b, attr)
        elif attr in A.x_delegated:
            return getattr(self.x, attr)
        else:
            raise AttributeError()

すべての属性を動的に委譲する必要がある場合、それはほぼ同じくらい簡単です。self.b初期化時または呼び出し時にの属性 (またはの) のリストを取得しself.b.__class__(4 つの可能性のうちどれを実行するかによって異なります)、それを static list の代わりに使用しますb_delegated

もちろん、これを名前 (_privateメソッドを削除するなど)、タイプ、または任意の述語 (callable属性を削除するなど) でフィルタリングできます。

または、上記のいずれかを組み合わせます。

とにかく、これは Python で (特に動的な) プロキシを行うための慣用的な方法です。完璧ではありませんが、別のメカニズムを発明しようとするのはおそらく良い考えではありません。

実際、完璧であることを意図したものではありません。これはあまり頻繁に行うべきではなく、行うときに偽装しようとしてもいけません。ユーザーがそれを知ることは実際に役立つため、actypes.cdllまたはモジュールが実際に別のものに委任されていることは明らかです。pyobjcあるクラスのパブリック インターフェイスのほとんどを別のクラスに委譲する必要があり、委譲についてユーザーに知られたくない場合は、その必要はないかもしれません。おそらく、プライベート オブジェクトを直接公開するか、オブジェクト モデルを再編成して、ユーザーが最初から適切な操作を行えるようにする方がよいでしょう。

于 2013-01-05T02:09:15.717 に答える
3

プロパティを作成するためのデコレータ構文があり、本格的なカスタム定義の記述子がありますが、setter/getter 疑似プライベート パターンは Python および Python コミュニティで積極的に推奨されていないため、実際には広く配布されたり一般的に使用されている方法はありません。あなたが探していることをするために。

プロキシ オブジェクトの場合__getattr__、 、__setattr__、およびを使用するか、または__getattribute__をだましてプロセスの早い段階で操作を試みることができます。__new__metaclass

于 2013-01-05T01:47:37.217 に答える
1
def make_property(parent, attr):
  def get(self):
    return getattr(getattr(self, parent), attr)
  def set(self, value):
    setattr(getattr(self, parent), attr, value)
  return property(get, set)

class A(object):
  def __init__(self, b): self.b = b
  c = make_property('b', 'c')
于 2013-01-05T01:53:06.380 に答える