Pythonでは、辞書(dict)データ構造はネストされた情報を保存するためによく使用されます。こうした構造をクローンする必要があるのは、開発者がテンプレート、設定、またはアプリケーションの部分間でデータを転送する際にしばしば直面します。
=による辞書の標準コピーは、単に元のオブジェクトへの参照を作成します。浅いコピー(shallow copy)は、辞書オブジェクトをコピーしますが、ネストされたオブジェクトはコピーしません。深いコピー(deep copy)は、内部のすべてのオブジェクトを再帰的にコピーし、一方のコピーでの変更が他方に影響を与えるのを防ぎます。
浅いコピーにはdict.copy()やdict()コンストラクタを使用できます。一方、深いコピーにはcopyモジュールとdeepcopy()関数を使用します:
import copy d = {"a": 1, "b": {"c": 2}} shallow_d = d.copy() deep_d = copy.deepcopy(d) # これでshallow_d['b']['c']の変更はd['b']['c']に影響します # deep_d['b']['c']の変更は元の辞書には影響しません
主な特徴:
dict.copy()は1階層深いコピーを行うことができますか?
いいえ、dict.copy()は浅いコピーしか作成しません。ネストされた辞書は、元の辞書と同じオブジェクトへの参照になります。
構造に不変オブジェクト(例えば、タプル)がある場合、deepcopyはそれを深くコピーしますか?
Deepcopyは、変更可能なネストされたオブジェクトのみをコピーします。不変オブジェクトはそのままとなります—タプル、文字列、数値は再帰的にコピーされることはなく、単にコピーに移されます。
深いコピーにjson.loads(json.dumps(dict))によるシリアル化を利用できますか?
可能ですが、制約があります。この方法はシリアル化可能なタイプにのみ機能し、辞書にシリアル化できないオブジェクト(例えば関数やカスタムクラス)がある場合は適していません:
import json orig = {"a": 10, "b": [1,2,3]} copy_like_deep = json.loads(json.dumps(orig)) # 複雑なオブジェクトには機能しません
** ネガティブケース
開発者はcopy()を使って設定をクローンし、ネストされた値を変更し、これが2つの独立した構造であると考えます。
利点:
簡単で迅速
欠点:
一方のコピーでのネストされたオブジェクトの変更がすべてに反映され—デバッグが難しいバグ。
** ポジティブケース
開発者は常にネストされた構造に対してcopy.deepcopy()を使用し、元の辞書が平坦に見えてもです。
利点:
データの独立性が保証され、バグが最小限に抑えられる
欠点:
Deepcopyは遅く、より多くのメモリを消費し、時には過剰になります。