yuki_H_Web
@yuki_H_Web (H yuki)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Pythonで2次元配列を作った時の処理の違いについて

解決したいこと

[0]が入った配列を3 * 3だけ作った後、その中身を入れようとすると同じ操作をしているように見えて結果が変わってくるということについて質問したいです。

mass = [[0] * 3 for _ in range(3)]
>>> print(mass)
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> mass[1][1] = 2
>>> print(mass)
[[0, 0, 0], [0, 2, 0], [0, 0, 0]]
mass = [[0] * 3] * 3
print(mass)
>[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
mass[1][1] = 2
[[0, 2, 0], [0, 2, 0], [0, 2, 0]]

上では正しい位置に2を代入することができたのですが、下のように配列を作ると全ての1つ目の場所に2が挿入されてしまっています。

最初のmassの作り方の違いが影響を与えているのは分かるのですが、どういった理由で違いが生まれているのでしょうか?
教えていただけると幸いです。

0

1Answer

そこまで私も詳しくないので若干語弊があるかもしれませんが、上の書き方だと内部のリストはそれぞれ別のオブジェクトで生成されています!

一方で下の書き方の場合、2次元目のデータは別のデータではなく同じデータ(同じデータへの参照)となっています!(整数や文字列の場合は基本的にコピーが取られますが、リストや辞書などはデータが巨大になるケースもあり今回のようにコピーが取られない・・・というケースがたくさんあります)

別のデータになっているか、同じデータになっているかはid関数で調べられます!(この辺のCのアドレス的な話はここでは深く触れませんが、リンク先で少し触れられているので読んでみていただいてもいいかもしれません)

試しに上のもので内部のリストをid関数を通してみると各データで別のidが割り振ってあることが確認できます。

mass = [[0] * 3 for _ in range(3)]
print(id(mass[0]))
print(id(mass[1]))
print(id(mass[2]))
36078824
36681672
36266632

一方で下の書き方で試してみると、同じid(同じデータ)が格納されていることが確認できます。同じデータになっているので更新したら他のインデックスも更新されてしまいます!

mass = [[0] * 3] * 3
print(id(mass[0]))
print(id(mass[1]))
print(id(mass[2]))
17037384
17037384
17037384
1Like

Comments

  1. @yuki_H_Web

    Questioner

    意識せずにリスト * 3 をしていましたが、深いコピー(?)になっていて同じデータになってしまっているとは・・・。
    質問の回答ありがとうございます!勉強になりました!

Your answer might help someone💌