copy --- 浅いコピーおよび深いコピー操作

ソースコード: Lib/copy.py


Python において代入文はオブジェクトをコピーしません。代入はターゲットとオブジェクトの間に束縛を作ります。ミュータブルなコレクションまたはミュータブルなアイテムを含むコレクションについては、元のオブジェクトを変更せずにコピーを変更できるように、コピーが必要になることが時々あります。このモジュールは、汎用的な浅い (shallow) コピーと深い (deep) コピーの操作 (以下で説明されます) を提供します。

以下にインターフェースをまとめます:

copy.copy(obj)

obj の浅い (shallow) コピーを返します。

copy.deepcopy(obj[, memo])

obj の深い (deep) コピーを返します。

copy.replace(obj, /, **changes)

obj と同じ型の新しいオブジェクトを作成し、フィールドを changes の値で置き換えます。

Added in version 3.13.

exception copy.Error

モジュール特有のエラーを送出します。

浅い (shallow) コピーと深い (deep) コピーの違いが関係するのは、複合オブジェクト (リストやクラスインスタンスのような他のオブジェクトを含むオブジェクト) だけです:

  • 浅いコピー (shallow copy) は新たな複合オブジェクトを作成し、その後 (可能な限り) 元のオブジェクト中に見つかったオブジェクトに対する 参照 を挿入します。

  • 深いコピー (deep copy) は新しい複合オブジェクトを作成し、元のオブジェクトに含まれるオブジェクトを再帰的に コピー して挿入します。

深いコピー操作には、しばしば浅いコピー操作の時には存在しない 2 つの問題がついてまわります:

  • 再帰的なオブジェクト (直接または間接に自分自身への参照を含む複合オブジェクト) は、再帰ループを引き起こすことがあります。

  • 深いコピーは何もかもコピーしてしまうため、例えば複数のコピー間で共有するつもりだったデータも余分にコピーしてしまいます。

deepcopy() 関数では、これらの問題を以下のようにして回避しています:

  • 現時点でのコピー過程ですでにコピーされたオブジェクトの memo 辞書を保持する。

  • ユーザ定義のクラスでコピー操作やコピーされる内容の集合を上書きできるようにする。

このモジュールでは、モジュール、メソッド、スタックトレース、スタックフレーム、ファイル、ソケット、ウィンドウ、その他これらに類似の型をコピーしません。このモジュールでは元のオブジェクトを変更せずに返すことで関数とクラスを (浅くまたは深く)「コピー」します。これは pickle モジュールでの扱われかたと同じです。

多くのコレクションでは、対応する copy() メソッド (list.copy()、dict.copy()、set.copy() など) で浅いコピーを作成できます。 また、リストやバイト配列などのシーケンスでは、全体のスライス (sequence[:]) を作成することでも浅いコピーを作れます。 ただし、これらのメソッドやスライス操作は、サブクラスのインスタンスをコピーするときに基底型のインスタンスを作成することがありますが、copy.copy() は通常、同じ型のインスタンスを返します。

クラスは、pickle 化の制御に使うのと同じインターフェースでコピーを制御できます。 これらのメソッドについては、pickle モジュールの説明を参照してください。 実際、copy モジュールは copyreg モジュールに登録された pickle 関数を使用します。

クラス独自のコピー処理を実装するには、特殊メソッド __copy__() と __deepcopy__() を定義できます。

object.__copy__(self)

浅いコピー操作を実装するために呼び出されます。 追加の引数は渡されません。

object.__deepcopy__(self, memo)

深いコピー操作を実装するために呼び出されます。 引数として memo 辞書が 1 つ渡されます。 __deepcopy__ の実装内で構成要素の深いコピーが必要な場合は、第 1 引数にその構成要素、第 2 引数に memo 辞書を渡して deepcopy() 関数を呼び出す必要があります。 memo 辞書は内部構造に立ち入らない不透明なオブジェクトとして扱ってください。

copy.replace() 関数は copy() や deepcopy() より制限が多く、namedtuple() で作成した名前付きタプル、dataclasses、および __replace__() メソッドを定義するクラスのみをサポートします。

object.__replace__(self, /, **changes)

このメソッドは、フィールドを changes の値で置き換えた、同じ型の新しいオブジェクトを作成する必要があります。

Added in version 3.13.

参考

pickle モジュール

オブジェクト状態の取得と復元をサポートするために使われる特殊メソッドについて議論されています。