Python deepcopy()とは?ネストしたリストを完全にコピーする方法

Pythonのdeepcopy()は、リストなどのオブジェクトを内部の要素まで含めて完全にコピーするための関数です。
特に、リストの中にリストが入っている「ネストしたリスト」をコピーするときに役立ちます。
通常のcopy()では、ネストしたリストの内部まで完全にコピーされないため、コピー先を変更すると元のリストまで変わってしまう場合があります。
この記事では、Pythonのdeepcopy()の基本的な使い方から、copy()との違い、ネストしたリストを安全にコピーする方法まで初心者向けに解説します。
Pythonのdeepcopy()とは?
deepcopy()は、Pythonのcopyモジュールに用意されている関数です。
基本的な使い方は次のとおりです。
import copy
コピー先 = copy.deepcopy(コピー元)
例えば、単純なリストをコピーできます。
import copy
numbers = [10, 20, 30]
new_numbers = copy.deepcopy(numbers)
print(new_numbers)
実行結果:
[10, 20, 30]
deepcopy()を使うと、元のリストとは別のオブジェクトとしてコピーできます。
ネストしたリストをdeepcopy()する
deepcopy()が特に重要になるのが、リストの中にリストが入っている場合です。
例えば、次のようなリストです。
numbers = [[1, 2], [3, 4]]
このような構造をネストしたリストと呼びます。
deepcopy()を使ってコピーしてみましょう。
import copy
numbers = [[1, 2], [3, 4]]
new_numbers = copy.deepcopy(numbers)
new_numbers[0][0] = 100
print(numbers)
print(new_numbers)
実行結果:
[[1, 2], [3, 4]]
[[100, 2], [3, 4]]
コピー先のnew_numbersを変更しても、元のnumbersには影響していません。
これがdeepcopy()の大きな特徴です。
copy()ではネストしたリストに注意
通常のcopy()でもリストをコピーできます。
import copy
numbers = [[1, 2], [3, 4]]
new_numbers = copy.copy(numbers)
しかし、ネストしたリストでは注意が必要です。
import copy
numbers = [[1, 2], [3, 4]]
new_numbers = copy.copy(numbers)
new_numbers[0][0] = 100
print(numbers)
print(new_numbers)
実行結果:
[[100, 2], [3, 4]]
[[100, 2], [3, 4]]
コピー先のnew_numbersを変更したにもかかわらず、元のnumbersまで変更されています。
これは、copy()が浅いコピー(shallow copy)だからです。
deepcopy()とcopy()の違い
copy()とdeepcopy()の違いを簡単にまとめると次のようになります。
| 方法 | コピーする範囲 | ネストしたリスト |
|---|---|---|
copy.copy() |
外側のオブジェクト | 内部オブジェクトは共有 |
copy.deepcopy() |
内部のオブジェクトまで | 独立してコピー |
例えば、
import copy
numbers = [[1, 2], [3, 4]]
shallow = copy.copy(numbers)
deep = copy.deepcopy(numbers)
という場合、
numbers
├─ [1, 2]
└─ [3, 4]
shallow
├─ [1, 2] ← 共有
└─ [3, 4] ← 共有
deep
├─ [1, 2] ← 別オブジェクト
└─ [3, 4] ← 別オブジェクト
という違いがあります。
deepcopy()なら3重のネストもコピーできる
deepcopy()は、さらに深いネストにも対応できます。
import copy
data = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
new_data = copy.deepcopy(data)
new_data[0][0][0] = 100
print(data)
print(new_data)
実行結果:
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
[[[100, 2], [3, 4]], [[5, 6], [7, 8]]]
元のdataには変更が反映されません。
このように、deepcopy()は内部にさらにリストや辞書などが入っている複雑なデータ構造をコピーするときに便利です。
deepcopy()の基本構文
deepcopy()の構文は次のとおりです。
copy.deepcopy(オブジェクト)
例えば、
import copy
new_data = copy.deepcopy(data)
と書きます。
deepcopy()はcopyモジュールに含まれているため、最初にインポートが必要です。
import copy
deepcopy()は元のリストを変更しない
deepcopy()を使って作成したコピーは、元のオブジェクトとは独立しています。
import copy
original = [[10, 20], [30, 40]]
copied = copy.deepcopy(original)
copied[0].append(50)
print(original)
print(copied)
実行結果:
[[10, 20], [30, 40]]
[[10, 20, 50], [30, 40]]
copiedだけが変更されています。
deepcopy()と代入の違い
次のような代入では、リストそのものをコピーしているわけではありません。
numbers = [10, 20, 30]
new_numbers = numbers
この場合、numbersとnew_numbersは同じリストを参照します。
new_numbers.append(40)
print(numbers)
実行結果:
[10, 20, 30, 40]
一方、deepcopy()なら別のオブジェクトになります。
import copy
numbers = [10, 20, 30]
new_numbers = copy.deepcopy(numbers)
new_numbers.append(40)
print(numbers)
print(new_numbers)
実行結果:
[10, 20, 30]
[10, 20, 30, 40]
deepcopy()はいつ使う?
deepcopy()は、コピーしたデータを変更しても元のデータに影響させたくない場合に使います。
特に次のようなケースで便利です。
-
ネストしたリストをコピーする
-
リストの中に辞書が入っている
-
辞書の中にリストが入っている
-
複雑なデータ構造を複製する
-
元データを保存したままコピー側を変更する
例えば、次のようなデータです。
data = [
{"name": "田中", "scores": [80, 90]},
{"name": "佐藤", "scores": [70, 85]}
]
このようなデータを完全に独立させてコピーしたい場合にdeepcopy()が役立ちます。
import copy
new_data = copy.deepcopy(data)
deepcopy()とスライスの違い
リストでは、スライスを使ってコピーすることもできます。
numbers = [10, 20, 30]
new_numbers = numbers[:]
しかし、これも基本的には浅いコピーです。
ネストしたリストでは、
numbers = [[1, 2], [3, 4]]
new_numbers = numbers[:]
new_numbers[0][0] = 100
print(numbers)
実行結果:
[[100, 2], [3, 4]]
元のリストにも変更が反映されます。
ネストしたリストを独立させたい場合は、
import copy
new_numbers = copy.deepcopy(numbers)
とします。
deepcopy()とlist.copy()の違い
リストにはcopy()メソッドもあります。
numbers = [10, 20, 30]
new_numbers = numbers.copy()
これは便利ですが、list.copy()も浅いコピーです。
つまり、
numbers = [[1, 2], [3, 4]]
new_numbers = numbers.copy()
new_numbers[0][0] = 100
とすると、元のnumbersにも変更が反映されます。
ネストしたリストを完全にコピーしたい場合は、
import copy
new_numbers = copy.deepcopy(numbers)
を使います。
deepcopy()の注意点
deepcopy()は便利ですが、常に使えばよいというわけではありません。
単純なリストなら、
numbers = [1, 2, 3]
のようなデータであれば、通常のコピー方法でも十分です。
例えば、
new_numbers = numbers.copy()
で問題ありません。
deepcopy()は内部のオブジェクトまでコピーするため、複雑なデータ構造では処理やメモリ使用量が大きくなる場合があります。
そのため、
ネストしたオブジェクトまで独立させたいときにdeepcopy()を使う
と覚えるとよいでしょう。
元の変数まで変わってしまうときは
代入やコピーのあとに元のデータまで変わってしまう原因と対策は、次の記事で症状別にまとめています。
Python deepcopy()まとめ
Pythonのdeepcopy()は、オブジェクトを内部のオブジェクトまで含めて独立した形でコピーするための関数です。
基本的な使い方は、
import copy
new_data = copy.deepcopy(data)
です。
特に重要なのは、copy()との違いです。
copy()
↓
浅いコピー
↓
内部オブジェクトを共有する場合がある
deepcopy()
↓
深いコピー
↓
内部オブジェクトもコピーする
そのため、ネストしたリストを完全にコピーしたい場合はdeepcopy()が便利です。
import copy
original = [[1, 2], [3, 4]]
copied = copy.deepcopy(original)
copied[0][0] = 100
print(original)
print(copied)
実行結果:
[[1, 2], [3, 4]]
[[100, 2], [3, 4]]
「元のリストを残したまま、ネストしたデータを自由に変更したい」ならdeepcopy()と覚えておきましょう。
Pythonの関数・メソッドの全体像はPython基本関数・メソッド完全一覧にまとめています。






