Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

copyとdeepcopyとnumpy.copyの挙動について

More than 3 years have passed since last update.

ハマったのでメモ.

コピーなし・浅いコピー・深いコピー

pythonでlistを別の変数に代入すると,「参照渡し」になる.

x = [1, 2, 3]
y = x
y[0] = 999
x  # yへの変更がxにも影響を及ぼした.

>>> [999, 2, 3]

これを回避 (= 値渡し) するためには,copyを使うと良い.

from copy import copy
x = [1, 2, 3]
y = copy(x)  # x[:]でも良い (むしろこっちのほうがシンプル)
y[0] = 999
x  # yへの変更が影響しなかった

>>> [1, 2, 3]

ではcopyは完全に行われたのか,というと,そうではない.
例えば,入れ子にされたlistについては参照渡しになっている.

from copy import copy
x = [[1, 2, 3], 4, 5]
y = copy(x)
y[0][0] = 999
x  # copyしたハズなのに!

>>> [[999, 2, 3], 4, 5]

そこで,入れ子等を含め何もかもを完全にcopyしたい場合はdeepcopyを使う.

from copy import deepcopy
x = [[1, 2, 3], 4, 5]
y = deepcopy(x)
y[0][0] = 999
x

>>> [[1, 2, 3], 4, 5]

NumPyはどうなのか.

試してみたところ,どうやら浅いコピーと深いコピーのどちらを実行するか自動で判断されるようである.
以下の2つは,x内の2番目のリストに6が含まれるかどうかだけが異なる.

import numpy as np
x = [[1, 2, 3], [4, 5]]
y = np.copy(x)
y[0][0] = 999
x

>>> [[999, 2, 3], [4, 5, 6]]
import numpy as np
x = [[1, 2, 3], [4, 5, 6]]
y = np.copy(x)
y[0][0] = 999
x

>>> [[1, 2, 3], [4, 5, 6]]

どうも,n次元配列に直せそうなものに対しては深いコピーを実施するようである.
行列がlistの入れ子で表現される以上まっとうな考えかただと思う.
ちなみに3次元でも同様である.

import numpy as np
x = [[[1, 0], [2, 0], [3]],
     [[4, 0], [5, 0], [6, 0]]]
y = np.copy(x)
y[0][0][0] = 999
x

>>> [[[999, 0], [2, 0], [3]], [[4, 0], [5, 0], [6, 0]]]
import numpy as np
x = [[[1, 0], [2, 0], [3, 0]],
     [[4, 0], [5, 0], [6, 0]]]
y = np.copy(x)
y[0][0][0] = 999
x

>>> [[[1, 0], [2, 0], [3, 0]], [[4, 0], [5, 0], [6, 0]]]

感想

deepcopy最強!!!!!

(一応) 公式曰く,深いコピー操作には2つの問題が有るとのこと.

  • 再起的なオブジェクトをコピーするときに無限ループしてしまう
  • 共有すべき管理データを余分にコピーしてしまう

でも個人で扱うぶんには多少冗長なコピーがあっても痛くない.
再帰処理だってそう頻繁に必要とされるものじゃないし,とりあえずハマりそうなシチュエーションではdeepcopyしとくってのは良い選択かもしれないですね.

mytk0u0
ほぼ全ての記事を手探りで得た知見の共有として書いています。間違っていたり非効率だったりするものもあるかと思います。その場合はご指摘いただけると嬉しいです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away