8.17. "copy" --- 浅いコピーおよび深いコピー操作
***********************************************

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

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

copy.copy(x)

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

copy.deepcopy(x)

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

exception copy.error

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

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

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

* *深いコピー (deep copy)* は新たな複合オブジェクトを作成し、その後
  元 のオブジェクト中に見つかったオブジェクトの *コピー* を挿入します
  。

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

* 再帰的なオブジェクト (直接、間接に関わらず、自分自身に対する参照を
  持 つ複合オブジェクト) は再帰ループを引き起こします。

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

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

* 現在のコピー過程ですでにコピーされたオブジェクトからなる、"メモ"
  辞 書を保持します; かつ

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

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

辞書型の浅いコピーは "dict.copy()" で、リストの浅いコピーはリスト全体
を指すスライス (例えば "copied_list = original_list[:]") でできます。

バージョン 2.5 で変更: 関数コピーの追加。

クラスでは、pickle 化を制御するためのインタフェースと同じインタフェー
スをコピーの制御に使うことができます。これらのメソッドに関する情報は
"pickle" モジュールの記述を参照してください。 "copy" モジュールは
pickle 用関数登録モジュール "copy_reg" を使いません。

クラス独自のコピー実装を定義するために、特殊メソッド "__copy__()" およ
び "__deepcopy__()" を定義することができます。前者は浅いコピー操作を実
装するために使われます; 追加の引数はありません。後者は深いコピー操作を
実現するために呼び出されます; この関数には単一の引数としてメモ辞書が渡
されます。 "__deepcopy__()" の実装で、内容のオブジェクトに対して深いコ
ピーを生成する必要がある場合、 "deepcopy()" を呼び出し、最初の引数にそ
のオブジェクトを、メモ辞書を二つ目の引数に与えなければなりません。

参考:

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