これは何?
を読んで面白かったので色々試した。
前提
前述の記事からリンクされている文書 にある通り、
文字列、数、タプルのようなイミュータブルなターゲットでは、更新された値が計算されますが、入力変数に代入し返されはしません。
【略】
リストや辞書のようなミュータブルなターゲットでは、インプレースメソッドは更新を行うので、その後に代入をする必要はありません。
となっている。なので前述の記事のとおり、mutable なオブジェクトの場合
b=a;a+=x;print(b)
b=a;a=a+x;print(b)
では異なる結果が得られる。a+=x
って a=a+x
と同じだよね、と思い込んでいる人はこの仕様に足をすくわれて苦しむことがあるだろう。
足をすくわれる前に気づいてよかった。
色々試した
list, set, dic
a=[1];b=a;a+=[2];print(a,b)
#=> [1, 2] [1, 2]
a={1:2};b=a;a|={3:4};print(a,b)
#=> {1: 2, 3: 4} {1: 2, 3: 4}
a={1,2};b=a;a|={3,4};print(a,b)
#=> {1, 2, 3, 4} {1, 2, 3, 4}
このとおり、 +=
は in-place になる。
string, tuple
a="xy";b=a;a+="z";print(a,b)
#=> xyz xy
a=(1,2);b=a;a+=(5,6);print(a,b)
#=> (1, 2, 5, 6) (1, 2)
string
と tuple
は immutable なので in-place にならない。
ちなみに関係ないけど string
の %
は、%=
としても使える(今知った)。
a="[%s]";b=a;a%="hoge";print(a,b)
#=>[hoge] [%s]
こちらも当然 in-place にはならない。
pathlib.Path
from pathlib import Path
a=Path("x");b=a;a/="y";print(a,b)
#=> x/y x
pathlib.Path
も immutable なのか。メソッド見るとなるほど自分を変更する手段はなさそうだ。
np.array
a=np.array([1]);b=a;a+=[10];print(a,b)
#=> [11] [11]
ちなみに [:]
の動作が組み込み配列と np.array
で異なるので
x=[1];y=x[:];x+=[10];print(x,y)
#=> [1, 10] [1]
x=np.array([1]);y=x[:];x+=[10];print(x,y)
#=> [11] [11]
と、動作が違うので要注意。
byte と bytearray
x=b'p';y=x;x+=b'q';print(x,y)
#=> b'pq' b'p'
x=bytearray(b'p');y=x;x+=b'q';print(x,y)
#=> bytearray(b'pq') bytearray(b'pq')
byte
と bytearray
で動作が異なる。まあ immutable かどうかで変わると言っているんだからそうだろう。
frozenset
frozenset
というものがあるのか。
frozendict
と frozenlist
はないのかな。
a=frozenset({1,2});b=a;a|={4};print(a,b)
#=> frozenset({1, 2, 4}) frozenset({1, 2})
set
と異なり、immutable なので in-place にはならない。まあそうだよね。
collections の人たち
もっと色々あるかと思ったら、 deque
ぐらいしかないのかな。
a=deque([1,2]);b=a;a+=[3];print(a,b)
#=> deque([1, 2, 3]) deque([1, 2, 3])
date, timedelta
a=date(2021,2,3);b=a;a+=timedelta(99);print(a,b)
#=> 2021-05-13 2021-02-03
p=timedelta(11);q=p;p+=timedelta(9);print(p,q)
#=> 20 days, 0:00:00 11 days, 0:00:00
date
も timedelta
も immutable らしい。
まとめ
というわけで、組み込みライブラリ周辺ではちゃんと
- immutable なら 非 in-place
- mutable なら in-place
となっていて、このルールからの逸脱は見つけられなかった。
もっと他に +=
、 |=
、 /=
、 ^=
の類を試したら良さげなものがあったらお知らせください。