Pythonのcopyとdeepcopyの使い方【浅いコピーと深いコピーの違い】

Pythonでの浅いコピーと深いコピーの違いについて解説します。

Pythonのcopyとdeepcopyの使い方【浅いコピーと深いコピーの違い】

プログラミングにおいて、浅いコピー(shallow copy)と深いコピー(deep copy)という概念があります。この違いを理解しないとおかしなバグに繋がる可能性もあるため、きちんと理解するようにしましょう。

浅いコピー(shallow copy)と深いコピー(deep copy)の違い

Pythonにおいて、オブジェクトのコピーには浅いコピーと深いコピーの2種類があります。

浅いコピー(shallow copy)は、オリジナルオブジェクトの参照をコピーしますが、オブジェクト内の子オブジェクトはコピーされません。つまり、新しく作成されたコピーとオリジナルのオブジェクトが、子オブジェクトについて同じ参照を持っています。そのため、コピーの子オブジェクトを変更すると、オリジナルオブジェクトも影響を受けます。

一方、深いコピー(deep copy)は、オリジナルオブジェクトの子オブジェクトまで完全に新しいコピーを作成します。これにより、新しく作成されたコピーとオリジナルのオブジェクトが、子オブジェクトについて独立した参照を持っています。そのため、コピーの子オブジェクトを変更しても、オリジナルオブジェクトは影響を受けません。

Pythonで浅いコピー(shallow copy)をする方法(copy(), copy.copy()を使う)

浅いコピーは、オブジェクトの参照をコピーしますが、子オブジェクトはコピーされません。つまり、子オブジェクトに加えた変更は、元のオブジェクトとコピー後のオブジェクトの両方に影響します。

Pythonでは、リストや辞書のcopy()メソッドを使ったり、copyモジュールのcopy.copy()関数を使用して浅いコピーを作成できます。それぞれの方法について具体例を用いて説明します。

# リストと辞書のcopy()メソッド

# リストの例
a = [1, 2, [3, 4]]
b = a.copy()
b[0] = 10 # オリジナルオブジェクトの変更
b[2][0] = 30 # 子オブジェクトの変更

# aの子オブジェクトはbの子オブジェクトと同じ参照を持っている
print(a)
# [1, 2, [30, 4]]

print(b)
# [10, 2, [30, 4]]


# 辞書の例
person1 = {'name': 'Alice', 'age': 30, 'hobbies': ['reading', 'traveling']}
person2 = person1.copy()
person2['age'] = 31 # オリジナルオブジェクトの変更
person2['hobbies'].append('cooking') # 子オブジェクトの変更

# person1の子オブジェクトも変更されてしまう
print(person1)
# {'name': 'Alice', 'age': 30, 'hobbies': ['reading', 'traveling', 'cooking']}

print(person2)
# {'name': 'Alice', 'age': 31, 'hobbies': ['reading', 'traveling', 'cooking']}
# copyモジュールを使った浅いコピー

import copy

a = [1, 2, [3, 4]]
b = copy.copy(a)
b[0] = 10
b[2][0] = 30

print(a)
# [1, 2, [30, 4]]

print(b)
# [10, 2, [30, 4]]

Pythonで深いコピー(deep copy)をする方法(copy.deepcopy()を使う)

深いコピーは、オブジェクトの子オブジェクトまで完全に新しいコピーを作成します。Pythonでは、copyモジュールのcopy.deepcopy()関数を使用して深いコピーを作成できます。

# コピーであるbの子オブジェクトの変更がaに影響を与えない

import copy

a = [1, 2, [3, 4]]
b = copy.deepcopy(a)
b[2][0] = 30

print(a)
# [1, 2, [3, 4]]

ミュータブル(変更可能)なオブジェクト(リストや辞書)では、浅いコピーと深いコピーの違いが重要になります。イミュータブル(変更不可能)なオブジェクト(文字列やタプル)では、浅いコピーと深いコピーの違いはあまり影響がありません。これは、イミュータブルなオブジェクトは変更できないため、参照が同じでも問題が発生しにくいからです。

そのため、リストや辞書などのミュータブルなオブジェクトをコピーする場合にはその用途に応じて浅いコピーと深いコピーを使い分けるようにしましょう。

まとめ

浅いコピーと深いコピーは、Pythonでオブジェクトをコピーする方法です。

浅いコピーは、オブジェクトの参照をコピーするだけで子オブジェクトはコピーされません。深いコピーは、オブジェクトの子オブジェクトまで完全に新しいコピーを作成します。

ミュータブルなオブジェクトで子オブジェクトの変更を避けたい場合は、深いコピーを使用してください。ただし、深いコピーはメモリ消費やパフォーマンスに影響があるため、適切な方法を選択できるようになりましょう。