+= がリスト上で予期しない動作をするのはなぜですか? 質問する

+= がリスト上で予期しない動作をするのはなぜですか? 質問する

Python の演算子+=がリストに対して予期しない動作をしているようです。何が起こっているのか誰か教えてもらえますか?

class foo:  
     bar = []
     def __init__(self,x):
         self.bar += [x]


class foo2:
     bar = []
     def __init__(self,x):
          self.bar = self.bar + [x]

f = foo(1)
g = foo(2)
print f.bar
print g.bar 

f.bar += [3]
print f.bar
print g.bar

f.bar = f.bar + [4]
print f.bar
print g.bar

f = foo2(1)
g = foo2(2)
print f.bar 
print g.bar 

出力

[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3]
[1]
[2]

foo += barはクラスのすべてのインスタンスに影響しているように見えますが、foo = foo + barは期待どおりに動作するようです。

グーグルで検索してみましたが、オペレーターの正式な名前がわからない+=ため、何も見つけられませんでした。

ベストアンサー1

一般的な答えは、特別なメソッド+=を呼び出そうと__iadd__し、それが利用できない場合は__add__代わりに使用しようとする、ということです。つまり、問題はこれらの特別なメソッド間の違いにあります。

特殊__iadd__メソッドはインプレース追加用であり、作用するオブジェクトを変更します。__add__特殊メソッドは新しいオブジェクトを返し、標準+演算子にも使用されます。

したがって、+=演算子が定義されたオブジェクトで使用されると__iadd__、オブジェクトはインプレースで変更されます。それ以外の場合は、代わりにプレーンを使用して__add__新しいオブジェクトを返そうとします。

そのため、リストなどの可変型の場合は が+=オブジェクトの値を変更しますが、タプル、文字列、整数などの不変型の場合は の代わりに新しいオブジェクトが返されます (a += bは と同等になりますa = a + b)。

と の両方をサポートする型の場合__iadd____add__どちらを使用するか注意する必要があります。a += bは を呼び出し__iadd__て変更しますaが、 はa = a + b新しいオブジェクトを作成して に割り当てますa。 これらは同じ操作ではありません。

>>> a1 = a2 = [1, 2]
>>> b1 = b2 = [1, 2]
>>> a1 += [3]          # Uses __iadd__, modifies a1 in-place
>>> b1 = b1 + [3]      # Uses __add__, creates new list, assigns it to b1
>>> a2
[1, 2, 3]              # a1 and a2 are still the same list
>>> b2
[1, 2]                 # whereas only b1 was changed

不変型 ( がない場合__iadd__)ではa += b、 と はa = a + b同等です。これにより、不変型で を使用できるようになります。これは、そうでなければ数値などの不変型で+=を使用できないことを考慮すると、奇妙な設計上の決定のように思えるかもしれません。+=

おすすめ記事