Programmingバックエンド開発者

dictのshallow copyとdeep copyの違いは何ですか?Pythonでネストされた辞書を正しくコピーする方法は?

Hintsage AIアシスタントで面接を突破

回答。

質問の背景

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']の変更は元の辞書には影響しません

主な特徴:

  • 浅いコピーはオブジェクトの最初の「シェル」だけをコピーします
  • 深いコピーは構造内のすべてのオブジェクトを再帰的にコピーします
  • ネストされた構造を扱うときは、完全なコピーの独立性が必要な場合は常にdeepcopyを使用してください。

注意が必要な質問。

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は遅く、より多くのメモリを消費し、時には過剰になります。