みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

Pythonで一括代入する時の注意

Pythonでは複数の変数に一括して値を代入することができます.

a = b = 1
print(f"{a}, {b}. id={id(a)}, id={id(b)}")
b = 2
print(f"{a}, {b}. id={id(a)}, id={id(b)}")

これをPython3.8で実行すると,

1, 1. id=4347452064, id=4347452064
1, 2. id=4347452064, id=4347452096

となります.a = b = 1で,変数aとbに同じidのint 1が代入されています.b = 2では,変数bに別のidのint 2が代入されるので,aとbは異なる値となります.

このようにミュータブルな変数では直感的にうまく動作しますが,イミュータブルな変数では少し注意が必要です.

a = b = ["apple", "banana", "orange"]
print(f"{a}, {b}. id={id(a)}, id={id(b)}")
b[1] = "mango"
print(f"{a}, {b}. id={id(a)}, id={id(b)}")

これを実行すると,

['apple', 'banana', 'orange'], ['apple', 'banana', 'orange']. id=140672811873216, id=140672811873216
['apple', 'mango', 'orange'], ['apple', 'mango', 'orange']. id=140672811873216, id=140672811873216

となります.a = b = ["apple", "banana", "orange"]では変数aとbに代入されたlistは同じオブジェクトなので,b[1] = "mango"で変数bの要素を変更すると,オブジェクトそのものが変更されます.一見,変数aも変更されたように見えるのです.

この動作は便利な場合もありますが,今回のように一括代入する場合は不便なので,素直に深いコピーをします.

a = ["apple", "banana", "orange"]
b = a[:]
print(f"{a}, {b}. id={id(a)}, id={id(b)}")
b[1] = "mango"
print(f"{a}, {b}. id={id(a)}, id={id(b)}")

これを実行すると,

['apple', 'banana', 'orange'], ['apple', 'banana', 'orange']. id=140706788993536, id=140706785735872
['apple', 'banana', 'orange'], ['apple', 'mango', 'orange']. id=140706788993536, id=140706785735872

となり,期待通りに動作します.

このあたりの詳細は,3. データモデル — Python 3.8.3 ドキュメントに記載されています.

c = ; d = とすると、 c と d はそれぞれ二つの異なった、互いに一意な、新たに作成された空のリストを参照することが保証されています。 (c = d = [] とすると、 c と d の両方に同じオブジェクトを代入します)