2015年9月25日

python の加算代入演算子(+=)(プラスイコール)の注意点

python の一部のオブジェクト(list 等)では、「a = a + b」と「a += b」が同一視できない。
他言語経験者が思わぬバグを埋め込んでしまいそうな罠仕様・・・


>>> A = a = [1]
>>> a = a + [2]
>>> a, A, a is A
([1, 2], [1], False)
>>> # list の加算(+)は、元の a を変更しない
... # 加算の結果(新しい領域)を a に代入しているので、a と A は別オブジェクト
...

>>> B = b = [1]
>>> b += [2]
>>> b, B, b is B
([1, 2], [1, 2], True)
>>> # list の加算代入(+=)は、元の b を変更する
... # 加算代入しても新しい領域は割り当てられないので、b と B は同一オブジェクト
...

この理由は、list には 加算代入演算子(+=)用の __iadd__ メソッドが定義してあり、加算演算子(+)用の __add__ メソッド とは異なる動作になっているため。
※ list.__iadd__ の動作は list.extend と同じ。

__iadd__ メソッドが定義されてないオブジェクト(tuple 等)は、加算代入でも __add__ メソッドが使用される。
つまり、「a = a + b」と「a += b」 が同一視できる。

組み込みオブジェクトの大半には __iadd__ メソッドが定義されていないため、基本的に list とそのサブクラスを扱う際に注意すればいい。
加算代入演算子(+=)だけでなく、乗算代入演算子(*=)なども同様に注意。
ちなみに、__i???__ メソッドは、ミュータブルなオブジェクトに実装されるものらしい。

参考URL

0 件のコメント:

コメントを投稿