🐍
Pythonの複合代入演算子は代入演算子と等価ではなかった
TL;DL
- イミュータブルなオブジェクトでは複合代入演算子と代入演算子の挙動は同じ
- ミュータブルなリストなどでは複合代入演算子は破壊的な変更となる
複合代入演算子とは
-
+=,-=,*=,/=,//=,%=,**=,<<=,>>=,&=,^=,|=,@=(行列積)などのこと。 - 例えば
a = a + 1をa += 1のようにかける - これだけ見ると
a = a + 1のただの糖衣構文のようだが実はそうではないというはなし
ミュータブルなオブジェクトでは複合代入演算子は破壊的な変更となる
- Python は複合代入でまずインプレース演算(例:
__iadd__)を試み、なければ 通常演算(例:__add__)の結果を再代入する - listなどではこの
__iadd__がlist.extendのような動きをして破壊的変更となる
xs = [1, 2]
ys = xs # 同じリストを参照
xs += [3] # インプレース更新(extend 相当)
print(xs) # [1, 2, 3]
print(ys) # [1, 2, 3] ← 影響する!
xs = [1, 2]
ys = xs
xs = xs + [3] # 新しいリストを作る
print(xs) # [1, 2, 3]
print(ys) # [1, 2] ← 影響しない
だから何?
- 調子にのって「破壊的変更は良くない,非破壊的な処理でコードを書こう」とか思って
list.extendではなく複合代入演算子を使ったら,Claude Codeから鋭い指摘を受けました - pythonだと関数の引数のデフォルト値にミュータブルなオブジェクト使ったときの挙動など,引っかかりポイントがたまにあるのでこういうのは頭の片隅に入れておいたほうが良さそう
Discussion