【Python・アンチパターン】多次元リストの初期化

多次元リストの初期化時に演算子*を利用すると、想定外の動きをするので、アンチパターンとして記載。

目的

初期化された多次元リストを生成する。

アンチパターン

演算子*を用いて、初期化された多次元リストを生成すると、想定外の挙動をする。

具体的な事象

# NG
b_list = [[0]]*3
print(b_list) #[[0],[0],[0]]
b_list[0].append(1)
print(b_list) #[[0,1],[0,1],[0,1]]
  1. 演算子*を用いて、初期化された多次元リストを生成。

  2. その後、生成されたリストの先頭要素だけに1を追加すると、同処理が何故か全要素に適用される。

解説

演算子*について

演算子*は、a. (数値, 数値)b. (シークエンス, 整数)のように引数の型によって、以下のように作用が異なる。

  1. (数値, 数値):数値を共通の型に変換した後、掛け合わせた結果を返す。
  2. (シークエンス, 整数):シークエンスを整数回を繰り返した結果を返す。 ただし、整数が負の値の場合、空のシークエンスを返す。
b. (シークエンス, 整数)の処理内容について

シークエンス*整数の返す結果は、元のシークエンス上のオブジェクトのコピーではなく、同じオブジェクトへの参照のコピーである。

解決策

単純にfor文で繰り返すことで解決。

# OK
a_list = [[0] for _ in range(3)]
print(a_list) #[[0],[0],[0]]
a_list[0].append(1)
print(a_list) #[[0,1],[0],[0]]

参考