コピーの注意点
Pythonでオブジェクトをコピーする際には、いくつかの注意点があります。
この章では、参照渡しと値渡しの違い、ミュータブルとイミュータブルなオブジェクトの違い、コピー時のオブジェクトIDの変化、カスタムオブジェクトのコピーについて解説します。
参照渡しと値渡しの違い
Pythonでは、オブジェクトのコピーには参照渡しと値渡しの2種類があります。
参照渡し
オブジェクトへの参照(アドレス)が渡される。
オリジナルのオブジェクトとコピーされたオブジェクトが同じメモリ上のデータを参照しているため、片方を変更するともう片方も変更される。
値渡し
オブジェクトの値が渡される。
オリジナルのオブジェクトとコピーされたオブジェクトが別々のメモリ上のデータを参照しているため、片方を変更してももう片方は変更されない。
ミュータブルとイミュータブルなオブジェクトの違い
Pythonのオブジェクトには、ミュータブル(変更可能)とイミュータブル(変更不可)の2種類があります。
ミュータブル
リスト、辞書、集合など、要素の追加や削除、変更が可能なオブジェクト。
イミュータブル
数値、文字列、タプルなど、要素の追加や削除、変更ができないオブジェクト。
ミュータブルなオブジェクトをコピーする際には、参照渡しや浅いコピーでは意図しない動作が発生することがあるため、深いコピーを使用することが推奨されます。
コピー時のオブジェクトIDの変化
Pythonでは、オブジェクトのIDを «id()» 関数で取得できます。
オブジェクトをコピーした際に、オブジェクトIDが変化するかどうかで、参照渡しと値渡しを判断することができます。
import copy
original_list = [1, 2, 3]
shallow_copied_list = copy.copy(original_list)
deep_copied_list = copy.deepcopy(original_list)
print("オリジナルのID:", id(original_list))
print("浅いコピーのID:", id(shallow_copied_list))
print("深いコピーのID:", id(deep_copied_list))
オリジナルのID: 1692542043008
浅いコピーのID: 1692542042816
深いコピーのID: 1692542042752
この例では、オリジナルのリストと浅いコピー、深いコピーのリストのIDが異なることがわかります。
これにより、参照渡しではなく値渡しでコピーされていることが確認できます。
カスタムオブジェクトのコピー
Pythonで定義したカスタムオブジェクトも、 «copy.copy()» や «copy.deepcopy()» を使ってコピーすることができます。
ただし、カスタムオブジェクトの属性にミュータブルなオブジェクトが含まれている場合は、深いコピーを使用することが推奨されます。
import copy
class CustomObject:
def __init__(self, name, data):
self.name = name
self.data = data
original_obj = CustomObject("オリジナル", [1, 2, 3])
shallow_copied_obj = copy.copy(original_obj)
deep_copied_obj = copy.deepcopy(original_obj)
print("オリジナルのID:", id(original_obj))
print("浅いコピーのID:", id(shallow_copied_obj))
print("深いコピーのID:", id(deep_copied_obj))
オリジナルのID: 1692542056528
浅いコピーのID: 1692542099856
深いコピーのID: 1692542102416
この例でも、オリジナルのオブジェクトと浅いコピー、深いコピーのオブジェクトのIDが異なることがわかります。
これにより、参照渡しではなく値渡しでコピーされていることが確認できます。