Pythonのcopyとdeepcopyの使い方【浅いコピーと深いコピーの違い】
Pythonでの浅いコピーと深いコピーの違いについて解説します。
プログラミングにおいて、浅いコピー(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でオブジェクトをコピーする方法です。
浅いコピーは、オブジェクトの参照をコピーするだけで子オブジェクトはコピーされません。深いコピーは、オブジェクトの子オブジェクトまで完全に新しいコピーを作成します。
ミュータブルなオブジェクトで子オブジェクトの変更を避けたい場合は、深いコピーを使用してください。ただし、深いコピーはメモリ消費やパフォーマンスに影響があるため、適切な方法を選択できるようになりましょう。