4

私は「インプレース演算子」オーバーライド(たとえば+=)を持つクラスと、最初のインスタンスを@propertyに公開するクラスの2つのクラスを持っています。 (注:これは非常に問題を再現最小限に私の実際のコードから簡略化されです。)読み取り専用のプロパティを変更可能にするにはどうすればよいですか?

class MyValue(object): 
    def __init__(self, value): 
     self.value = value 

    def __iadd__(self, other): 
     self.value += other 
     return self 

    def __repr__(self): 
     return str(self.value) 

class MyOwner(object): 
    def __init__(self): 
     self._what = MyValue(40) 

    @property 
    def what(self): 
     return self._what 

さて、私が公開されたプロパティにその演算子を使用しようとすると:

>>> owner = MyOwner() 
>>> owner.what += 2 
AttributeError: can't set attribute 

私はそれがownerにプロパティを設定しようとしているので、これが期待されることがわかったから。 の設定をにすると、新しいオブジェクトのプロパティを設定することができますが、それでも私は(その場で)を変更してのオブジェクトを修正することができますか、これは単なる言語の奇妙なことですか?

(もthis questionを参照してくださいが、結局、私はそれは、Python 3で動作するようにしたいので、私は、好ましくのない古いスタイルのクラスに戻す、他の道を行くことにしようとしている)


その間、私は同じことをする方法でこれを解決しました。

class MyValue(object): 
    # ... 

    def add(self, other): 
     self.value += other 

>>> owner = MyOwner() 
>>> owner.what.add(2) 
>>> print(owner.what) 
42 
+1

その他の回避策: 'TEMP = owner.whatを。 temp + = 2'、[owner.what] [0] + = 2'のようになります。 –

+0

私はユーザーコードから「ハッキーな」部分を保ちたいので、@ Martijnの答えに行くつもりですが、アイデアに感謝します。彼らは他のもののために便利になるかもしれません。私は彼らが非常に簡潔であることを好む(特に第2::)。 – criptych

答えて

5

これは言語のクォークです。いないすべてのオブジェクトが変更可能であるため、これが必要である

object = object.__iadd__(value) 

object += value操作はに変換されます。上記の操作の割り当て部分に仮想ノーオペレーションをもたらす、selfが正しく返されます。以下が実行されるように、あなたの場合は

は、問題のobjectは、また属性です:

アパート( tmp = owner.what; tmp += 2のように)左側に、ここで object.whatを参照回避から
owner.what = owner.what.__iadd__(2) 

があり、これをきれいに処理する方法。

あなたは簡単にプロパティへの代入が同じオブジェクトとその上のゲートに関することを検出することができます

class MyOwner(object): 
    def __init__(self): 
     self._what = MyValue(40) 

    @property 
    def what(self): 
     return self._what 

    @what.setter 
    def what(self, newwhat): 
     if newwhat is not self._what: 
      raise AttributeError("can't set attribute") 
     # ignore the remainder; the object is still the same 
     # object *anyway*, so no actual assignment is needed 

デモ:

>>> owner = MyOwner() 
>>> owner.what 
40 
>>> owner.what = 42 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 24, in what 
AttributeError: can't set attribute 
>>> owner.what += 2 
>>> owner.what 
42 
+0

"これは言語の特徴です。"私はそれを恐れていた。私はあなたの提案をお試しいただきます、ありがとうございます。 – criptych

関連する問題