1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

スライスでコピーしている人!注意ですよ!

Last updated at Posted at 2025-01-12

はじめに

スライス表記を使うとこんな感じでコピーができますよね?

fruit = ['りんご', 'ぶどう', 'みかん']
fruit2 = fruit[:]

これ便利なのですが、これでコピーできるんだなーと意味も考えず使うと、よくない結果を招くので、筆者の失敗を交えて注意喚起しようと思います。

前提知識

前提知識として、ディープコピーとシャロ―コピーを知ってないと困るので、軽く話しておきます。

シャローコピー(shallow copy)

シャローコピーは、元のオブジェクトの「参照」をコピーするものです。つまり、コピーされたオブジェクトと元のオブジェクトが同じidを参照するということです。そのため、元のオブジェクトが変更されると、コピーされたオブジェクトにも影響します。その逆も然りです。

ここではわかりやすくするために簡単な数字やアルファベットで説明します。

a = [A, B, C]
b = a[:]    #aをシャロ―コピーしたもの([A, B, C]ということ)

id(a[0]), id(a[1]), id(a[2])    #1, 2, 3
id(a)    #4
id(b[0]), id(b[1]), id(b[2])    #1, 2, 3
id(b)    #5

こういうイメージでa[0]b[0]Aというオブジェクトを参照しています。なので、a[0]からAの中身を書き換えるとb[0]からAの中身を取ってくる時にも書き換わったものが得られる、という具合に相互に影響します。

ディープコピー(deep copy)

ディープコピーは、元のオブジェクトの「値」を完全にコピーするものです。コピーされたオブジェクトは独立したidを持つため、元のオブジェクトが変更されても影響を受けませんし、その逆も然りです。

こちらも簡単な数字やアルファベットで説明します。

import copy
a = [A, B, C]
b = copy.deepcopy(a)    #aをディープコピーしたもの([D, E, F]ということ)

id(a[0]), id(a[1]), id(a[2])    #1, 2, 3
id(a)    #4
id(b[0]), id(b[1]), id(b[2])    #5, 6, 7
id(b)    #8

こういうイメージで、b[0]Aと同じ値を持つDという別のオブジェクトを参照しています。なので、a[0]からAの中身を書き換えても、Dの中身は書き変わらないのでb[0]からDの中身を取ってくる時には影響しません。また、その逆も然りです。

本題

 筆者の失敗談を話します。筆者が失敗したのはお絵描きツールを作っているときです。redoundo機能を作るため、ピクセル情報を二次元リストにして、redo_stackundo_stackというリストにそれぞれ格納してました。しかし、格納する時点では正しい情報が、なぜかredoundoを実行するときにおかしくなってるんです。これの原因が、スライス表記でコピーするときは、シャロ―コピーだからだったんですよね。

色を塗った時に現在のピクセル情報が書き換わる

それをシャロ―コピーして作られたオブジェクトも全部同期して書き換わる。

こんな具合です。これのせいでredoしてもundoしてもなぜか絵が変わらない...保存したときのピクセルデータは正しく格納されてる...とよくわからず時間を取られてしまいました。
 ちゃんと考えれば、二次元リストの情報を格納するときに、シャロ―コピーを使っているのだから、格納した後に中身が同期して書き換わるのは当然のことです。しかし、コピーはめんどいからスライスでやっとけばいいや、という思考停止状態だと、このディープコピーとシャロ―コピーというポイントに全く思い当たらず、本当に原因不明の事態でした。

結論

多次元リストをコピーするときは、中身が同期してほしくないなら、ディープコピーを使っているか指さし確認する!

最後に

 ここまで読んで下さりありがとうございました。自分では理解しているつもりでも、理解できていないことって、やっぱりどっかでボロが出るんだなと思いました。こう言う文法が間違ってるとかじゃない、エラーが出ない間違いっていうのは、きっかけがないと気づきにくいですよね。今まさに、似たような原因で詰まっている人が、気づくきっかけになれば良いと思います。

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?