# 留年しても分かるPythonのshallow copyとdeep copy
tags: 情報
shallow copyとdeep copyの違いとか曖昧だけど必要になったら毎回ググればえーやろ^^
という精神で生きていたらググれない状況でそれを聞かれて破滅しました.こんなのも分からず生きていてごめんなさい...と思いましたが,他人がこれを知らなくても許せる優しい人間になりたい.
人にやさしく自分に厳しい人間になるのが夢です.
...俺を反面教師にして「ググったらえーだけやろ」という考えは捨てろ!今すぐだ!
そもそもPythonの代入文は
Pythonの代入文ではmutableなものはアドレスをコピーしているだけなので
# coding: utf-8 b = a = 123 b += 456 print("a = {}, b = {}".format(a, b)) d = c = [1, 2, 3] d.append(4) print("c = {}, d = {}".format(c, d)) f = e = "ariga10" f += "10" print("e = {}, f = {}".format(e, f))
と書くと出力は
a = 123, b = 579 c = [1, 2, 3, 4], d = [1, 2, 3, 4] e = ariga10, f = ariga1010
となります.リストはmutableなのでアドレスのコピーが変数に代入されて,それ以外はimmutableなオブジェクトなので値が代入されるというわけです.
mutableなものとしてはlist
, set
, dict
が挙げられます.
Copy
copy
というモジュールにあるcopy()
というメソッドを使うことで新しいオブジェクトを作り,この問題を解消できるのです.
しかし,ここにも問題があります.copy
にはshallow copyとdeep copyという違いがあることです.
ふざけるなよ...?なんで2つあるんだよ^^;
ちなみに,組み込みメソッドのcopy()
はshallow copy?だからPythonは嫌いなんだよ^^;
まあ落ち着けよ俺^^;
挙動
下のようなコードを書きます.
# coding: utf-8 import copy a = [1, 2, [3, 4]] b = copy.copy(a) b[0] = 29 b[2][0] = 4649 print("a = {}, b = {}".format(a, b)) c = [5, 6, [7, 8]] d = copy.deepcopy(c) d[0] = 810 d[2][0] = 114514 print("c = {}, d = {}".format(c, d))
これを実行すると以下のような結果を得ます.
a = [1, 2, [4649, 4]], b = [29, 2, [4649, 4]] c = [5, 6, [7, 8]], d = [810, 6, [114514, 8]]
copy.copy()
はshallow copy,つまり,mutableなオブジェクトの中のmutableなオブジェクトに関してはアドレスしか返さないです.
一方,copy.deepcopy()
はdeep copy,つまりmutableなオブジェクトの中のmutableなオブジェクトに関しても同じオブジェクトを作成して返します.
このコードでは変数a
内のリストを参照した値がb
のリストに入っているので,b
のリストの要素が変更されるとa
にまで影響が及びます.
図示すると下のようになります.
まとめ
- Pythonではmutableな値とimmutableな値のcopyには細心の注意を払おう
- ググればええやんは面接では通じないし,ググらなくてもいいようにした方がいいよ(N=1)
- 留年しそうになると頭がやられます