Programmingデータエンジニア

シャローコピー(浅いコピー)とディープコピー(深いコピー)の違い、及び複雑なオブジェクトをコピーする際のcopy.copyとcopy.deepcopyの動作について説明してください。間違った理解がバグにつながった例を挙げてください。

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

答え。

シャローコピー(shallow copy)は新しい上位オブジェクトを作成しますが、ネストされたオブジェクト(リストの要素、ネストされた辞書など)はオリジナルとメモリを共有します。ディープコピー(deep copy)はすべてのレベルのオブジェクトを再帰的にコピーします。

copyモジュールを使って実行できます:

import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # originalとshallowの両方を変更 print(original) # [[99, 2], [3, 4]] # では、deepで original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]

特徴:

  • copy.copy(obj):オブジェクトの「ラッパー」だけをコピーします
  • copy.deepcopy(obj):完全に再帰的にコピーします
  • 一部のオブジェクト(例えば、オープンファイルやソケット)はディープコピーされません(例外)

トリッキーな質問。

可変オブジェクトを含むタプルをコピーするとどうなりますか?

例を用いた答え:

tupleは不変ですが、その要素は可変の可能性があります(例えばリスト)。シャローコピーとディープコピーは異なります:

import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # ディープコピーの場合: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])

このテーマの細部を知らないことで発生した実際のエラーの例


物語

文書処理アプリケーションでは、データが辞書内のリストに保存されていました。copy.copyを使ってオブジェクトをコピーした際に、ネストされた要素が新しいオブジェクトの修正時に偶然変更されました。その結果、システムの他の部分で元のデータが変更されてしまいました!データが破損しました。deepcopyに置き換えることで修正しました。


物語

機械学習プロジェクトでは、モデルのハイパーパラメータを保存する際に、標準の代入とシャローコピーを通じて設定リストをコピーしました。その後、異なる実験が互いにパラメータを変更することになりました。ネストされたリストのコピーの挙動をdiagnoseした後にバグの原因を特定しました。


物語

金融ソフトウェアで、ディープコピーを偶然にもオープンファイル(ハンドル)を含むオブジェクトに適用し、TypeError: cannot pickle '_io.TextIOWrapper' objectが発生しました — なぜなら、copy.deepcopyは内部でpickleを使用しているからです。明示的にこれらのフィールドを処理するか、シャローコピーを呼び出すことで修正しました。