バグの素~間違いやすいところ

リストの初期化

問題

以下の処理を意図する。

  • 2次元リストを準備し、そのリストに1列追加する
  • 追加の際、各行を2行ずつに繰り返し、追加した列には全行を通したカウンター値を記録

これを意図したコードで以下のように意図しない結果となった。

原因

原因は14行目、19行目で複製すべきリストnew_rowを単純に代入しているためで、変数代入時に元のリストオブジェクトは複製されず重複して参照されるだけとなり、1つの変更が元のオブジェクトを通して全体に波及してしまう。

具体的にリストのi行目の処理を追うと以下の通り。

  1. 1回目のnew_row = source_list[i]で元リストのi行目が1次元リストとして共有される
  2. そのリストの最後尾にカウンター値が追加され、カウンターがインクリメントされる
    • この時点で1次元リストの最後尾にカウンター値が追加され、new_rowsource_list[i]のいずれにも参照されている
  3. 新しいリストに1次元リストが行として追加される
    • この時点で、source_list[i]new_rownew_list[2*i]が共通の1次元リストを参照している
  4. 2回目のnew_row = source_list[i]で元リストのi行目が共有される(実はこの処理は1番目の繰り返しであり意味がない)
  5. そのリストの最後尾にカウンター値が追加され、カウンターがインクリメントされる
    • この時点で、先に最後尾にカウンター値追加済みの1次元リストの最後尾に更にカウンター値が追加され、new_rowsource_list[i]のいずれにも参照されている
  6. 新しいリストに1次元リストが行として追加される
    • この時点で、source_list[i]new_rownew_list[2*i+1]が共通の1次元リストを参照している

この結果、source_listも以下のように変更される。

解決

この原因である重複参照を解消するため、元リスト各行の(参照を)代入するのではなく、copy()メソッドで新しいインスタンスを生成することで、想定した結果を得る。

結論

リストを代入するときに参照・複製を意識し、基本はcopy()で複製。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です