初期化したリストの更新処理でハマってしまった
今回は,初期化したリストを更新した際にハマってしまった失敗があるので,備忘録として残しておきます. 詳しい内容は参考サイトに載っています.(かなりわかりやすいです!)
python 決まった形のリストを予め作成しておきたい場合に,以下のようにすることがあると思います.
shape you want: [[0, 0], [0, 0], [0, 0]] # 要素が2つあるリストが3つ
>>> list1 = [[0] * 2] * 3
>>> list1
[[0, 0], [0, 0], [0, 0]]
そして,上記リストを何かしらの値で更新したい場合を考えます.
今回だと,[0][0]
の要素を更新するとします.
>>> list1[0][0] = 3.5
>>> list1
[[3.5, 0], [3.5, 0], [3.5, 0]]
結果は,各リストの0番目の要素が全て更新されています.
この原因は,list1 = [[0] * 2] * 3
と書くと,要素のリストが全て同じオブジェクトになってしまい,どこかの要素を変更すると全て変わってしまうからです.
対処法
上記の結果を回避するためにはリスト内包表記を使うと解決することができます. 先程の例の場合,以下のように書くといいです.
>>> list2 = [[0] * 2 for i in range(3)]
>>> list2
[[0, 0], [0, 0], [0, 0]]
内包表記を使うと,リストはそれぞれ異なるオブジェクトとして扱われます.
ですので,[0][0]
の要素を更新すると,意図した部分だけが更新され問題ありません.
>>> list2[0][0] = 3.5
>>> list2
[[3.5, 0], [0, 0], [0, 0]]
リストを初期化する際はこれらに注意しておかないと,本来の意図とは違う動きになってしまいます.
こうゆうミスを気にしたくない場合には,numpy の array で作りたい shape を作成し,その後にリストに変換すれば良いかもしれないです.
>>> np.zeros((2, 3)).tolist() # 0で初期化
[[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]
# 0以外の場合
np.ones((2, 3)).tolist() # 1で初期化
np.full((2, 3), 5).tolist() # 任意の値で初期化