Pythonの「浅いコピー」と「深いコピー」の違いとは?コピーの罠を徹底解説!

こんにちは。ゆうせいです。

プログラミングをしていると、「データを複製したい」場面ってよくありますよね。特にPythonでリストや辞書を扱うとき、元のデータを残しつつ、新しいデータで何か試したい…なんて考えるはずです。

「なんだ、簡単だよ。=(イコール)で代入すればいいんでしょ?」

そう思ったあなた、実はそこに大きな落とし穴があるかもしれません!

今日は、Pythonプログラミングで多くの初心者がつまずきやすい、「shallow copy(浅いコピー)」と「deep copy(深いコピー)」という重要な概念について、一緒に学んでいきましょう。

「コピー」の前に…「代入」がコピーじゃない?

まず、一番やってしまいがちな「代入」を見てみましょう。

original_list = [1, 2, [10, 20]]
copied_list = original_list

これで copied_list が original_list の複製になったように見えます。

では、copied_list の中身を変えてみたらどうなるでしょう?

copied_list[0] = 99
copied_list[2][0] = 999

print(f"コピーしたリスト: {copied_list}")
print(f"元のリスト: {original_list}")

実行結果はこうなります。

コピーしたリスト: [99, 2, [999, 20]]
元のリスト: [99, 2, [999, 20]]

あれ? copied_list を変えただけなのに、original_list まで変わってしまいました!

これはなぜでしょうか?

実は、Pythonの = での代入は、データを丸ごと複製しているわけではないんです。

original_list というのは、データ([1, 2, [10, 20]])が保存されている「場所の住所」を持っているようなものだと想像してください。

copied_list = original_list と書くことは、「copied_list さんにも、original_list さんが知っているのと同じ住所を教えます」という意味になります。

つまり、二人は同じ家(データ)を見ている状態です。

だから、copied_list さんが家の壁紙を変えたら([0] = 99)、original_list さんが家を見ても、当然壁紙は変わっていますよね。

これを「参照(リファレンス)を渡している」と呼びます。これでは独立したコピーとは言えません。

Shallow Copy(浅いコピー)とは?

「じゃあ、ちゃんと別の家(データ)を作りたい!」

そのために使うのが copy モジュールです。まずは「浅いコピー」から見ていきましょう。

copy.copy() を使います。

import copy

original_list = [1, 2, [10, 20]]
shallow_copied_list = copy.copy(original_list)

これは、「original_list とそっくりな、新しい家を建ててください」とお願いするイメージです。

では、さっきと同じように中身を変えてみましょう。

shallow_copied_list[0] = 99
print(f"浅いコピー: {shallow_copied_list}")
print(f"元のリスト: {original_list}")

実行結果:

浅いコピー: [99, 2, [10, 20]]
元のリスト: [1, 2, [10, 20]]

おお!今度は shallow_copied_list[0] を変えても、original_list[0] は変わりませんでした。新しい家が建った証拠です。

…しかし、油断は禁物です。

original_list の中には、さらに別のリスト [10, 20] が入っていましたね。

この「リストの中のリスト」を変えたらどうなるでしょう?

shallow_copied_list[2][0] = 999
print(f"浅いコピー: {shallow_copied_list}")
print(f"元のリスト: {original_list}")

実行結果:

浅いコピー: [99, 2, [999, 20]]
元のリスト: [1, 2, [999, 20]]

なんと!またしても元のリストが変わってしまいました!

これが「浅い」と呼ばれる理由です。

Shallow Copyは、例えるなら「家の間取りや家具(1 とか 2)は新しく用意するけど、家の中にある『金庫』は、元の家にある『金庫』の場所(住所)だけを教えておく」というコピー方法なんです。

[1, 2, [10, 20]] の [10, 20] の部分が、この「金庫」にあたります(専門用語では「ミュータブルなオブジェクト」と言います)。

shallow_copied_list は新しい家(リスト)ですが、その中にある「金庫の住所」は元のリストが持っている「金庫の住所」と全く同じ。

だから、どちらか一方から金庫の中身([10, 20] の 10)を変えると、もう一方から見ても変わってしまうのです。

Deep Copy(深いコピー)とは?

「もう!とにかく全部、完璧に複製して、お互い一切影響しないようにしたい!」

そんなときに登場するのが「深いコピー」、copy.deepcopy() です。

import copy

original_list = [1, 2, [10, 20]]
deep_copied_list = copy.deepcopy(original_list)

Deep Copyは、「家の間取りも家具も、そして家の中にある『金庫』も、その金庫の中身さえも!すべて丸ごと新しく作ってください」とお願いする方法です。

元のデータと全く同じものが、全く別の場所に、新しく作られます。

では、試してみましょう。

deep_copied_list[0] = 99
deep_copied_list[2][0] = 999

print(f"深いコピー: {deep_copied_list}")
print(f"元のリスト: {original_list}")

実行結果:

深いコピー: [99, 2, [999, 20]]
元のリスト: [1, 2, [10, 20]]

やりました!

今度こそ、deep_copied_list のどこを変更しても、original_list には一切影響がありません。

これこそが、私たちが最初にイメージしていた「完全な複製」ですね。

どう使い分ける?メリットとデメリット

では、いつでも Deep Copy を使えば良いのでしょうか?そうとも限りません。

Shallow Copy(浅いコピー)

  • メリット: Deep Copyに比べて処理が速く、メモリの使用量も少ないです。コピーするのが「浅い」階層だけだからですね。
  • デメリット: 今見たように、リストの中にリストがあるような複雑なデータ(入れ子構造)だと、意図せず元のデータを変更してしまう危険があります。
  • 使いどき: リストの中身が数値や文字列だけ(金庫がない状態)で、入れ子になっていない場合は、Shallow Copyで十分かつ高速です。

Deep Copy(深いコピー)

  • メリット: 元のデータと完全に切り離された、独立した複製を作れます。これが最大の強み。安心して複製側を変更できます。
  • デメリット: データが複雑になればなるほど、すべてを新しく作り直すため、処理に時間がかかり、メモリも多く消費します。
  • 使いどき: リストの中に別のリストや辞書が入っている場合や、元のデータに絶対に影響を与えたくない場合に必須です!

まとめと今後の学習

今回は、Pythonのコピーの仕組み、「参照(代入)」「浅いコピー」「深いコピー」について学びました。

  1. = での代入は、コピーではなく「同じ住所(参照)を見る」だけ。
  2. copy.copy() (浅いコピー) は、一番外側だけ新しく作る。中身(入れ子)は同じ住所を見る。
  3. copy.deepcopy() (深いコピー) は、中身の奥深くまで、すべてを新しく作る。

この違いを理解できると、データが意図せず書き換わってしまうバグを劇的に減らせますよ。

「なんだか難しかったな…」と感じたかもしれません。

でも大丈夫、この感覚はとても大切です。

今後さらに理解を深めるためには、「ミュータブル (Mutable)なオブジェクト」と「イミュータブル (Immutable)なオブジェクト」という概念を学ぶことを強くおすすめします。

簡単に言うと、「中身を変えられるデータ(リストや辞書など)」がミュータブルで、「中身を変えられないデータ(数値や文字列など)」がイミュータブルです。

今回の「金庫」の例えは、まさにミュータブルなオブジェクトのことだったんです。

この区別がつくようになると、「あ、このデータは浅いコピーで十分だな」「これは深いコピーじゃないと危ない!」と自分で判断できるようになります。

まずは、copy モジュールを使うときは、自分が扱っているデータに入れ子構造(リストの中のリストなど)がないか確認するクセをつけましょう!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。