2017-11-01 7 views
0

インプレースインデックス付け演算子を追加提供するには、以下のクラスは例外TypeError:...オブジェクトは、アイテムの割り当て

class Spam: 
    def __init__(self): 
     from collections import defaultdict 
     self.eggs = defaultdict(list) 
    def __getitem__(self, index): 
     class AdderHelper: 
      def __init__(self, eggs): 
       self.eggs = eggs 
      def __iadd__(self, egg): 
       self.eggs.append(egg) 
       return self 
     return AdderHelper(self.eggs[index]) 

を考えてみサポートしていません、私はイテレータと似(ヘルパークラスを定義しパターン)、クラスのインスタンスで呼び出される次のレベルの演算子を提供しました。

は例えば、私は私がのGetItemの結果を割り当てた場合、残念ながら、Pythonはそれを好きではなかったと興味深いことに

Traceback (most recent call last): 

    File "<ipython-input-82-ee0bba1041e3>", line 1, in <module> 
    spam[0] = 1 

TypeError: 'Spam' object does not support item assignment 

を訴え、次のオペレータの動作

spam = Spam() 
spam[0] += 1 

を提供することを目的とそれだけで動作します。

obj = spam[0] 
obj += 1 

は、インプレースを追加するために、私は単純に、それにもかかわらず行動 を理解していない、のようにそれがない、ルックスSetItem関数を呼び出し、それを乗り越えるための唯一の方法は、

def __setitem__(self, index, value): 
    obj = self.__getitem__(index) 
    obj += value 
    return self 
のように SetItem関数関数をオーバーライドすることです

Q1注:@vaultahスパム[0] + = 1 [0]スパム=基本的にスパムである[0] + 1

私ができなかった; tはそのパイソンをサポートする任意のドキュメントを見つけます第1オペランドを自己として、インプレース演算子をバイナリ演算として扱う。分解が他言う

def foo(spam): 
    spam[0] += 1 
dis.dis(foo) 
    2   0 LOAD_FAST    0 (spam) 
       2 LOAD_CONST    1 (0) 
       4 DUP_TOP_TWO 
       6 BINARY_SUBSCR 
       8 LOAD_CONST    2 (1) 
      10 INPLACE_ADD 
      12 ROT_THREE 
      14 STORE_SUBSCR 
      16 LOAD_CONST    0 (None) 
      18 RETURN_VALUE 
+0

'spam [0] = 1'は' __getitem__'ではなく '__setitem__'を呼び出します。 – vaultah

+0

@vaultah:申し訳ありませんが、入力ミスがありました – Abhijit

+0

私のポイントは依然として立っています。 'spam {0} + = 1'は基本的に' spam {0} = spam [0] +1} – vaultah

答えて

2

+=は、それが存在する場合、LHSの__iadd__メソッドを呼び出し増強代入演算子であり、は次にLHSにその戻り値を代入:

For instance, if x is an instance of a class with an __iadd__() method, x += y is equivalent to x = x.__iadd__(y) .

source

したがって

spam = Spam() 
spam[0] += 1 

spam = Spam() 
spam[0] = spam[0].__iadd__(1) 

に相当する__getitem__が実装されているためspam[0]が成功しているが、それが動作する__setitem__を必要とするので、spam[0]に続く割り当ては、ありません。同時に、spam[0].eggsリストは予想通り__iadd__作品以降、更新されています

In [4]: spam[0].eggs 
Out[4]: [1] 

は、関連するよくある質問のためthisを参照してください。

関連する問題