問題の背景:Pythonではオブジェクトのコピー(特にコレクション—リスト、辞書)は重要です。変数に単純に代入すると、新しい参照が作成され、コピーは作成されません。copy()とdeepcopy()の特別なメソッドは、構造の共同使用時に望ましくない「副作用」を避けるために登場しました。
問題:ネストされたコレクション(リストのリスト、辞書の中の辞書)を扱う場合、単純なcopy()はコンテナ自身だけをコピーしますが、内部の要素はコピーしません。これにより、ネストされた要素の変更がすべての「コピー」に反映されるという見落としがちなバグが発生する可能性があります。
解決策:copy.copy()は浅いコピー(shallow copy)を作成します — 新しい上位コンテナを作成しますが、ネストされたオブジェクトは同じままです。copy.deepcopy()はすべてのネストされたオブジェクトを再帰的にコピーします。
コードの例:
import copy lst = [[1, 2], [3, 4]] shallow = copy.copy(lst) deep = copy.deepcopy(lst) lst[0][0] = 10 print(shallow) # [[10, 2], [3, 4]] — ネストされたオブジェクトが変更されました! print(deep) # [[1, 2], [3, 4]] — deepcopyは元の状態を保持しました
主な特徴:
listをコピーするためにlst2 = lst[:]と書くだけで十分ですか?
lst2 = lst[:]はリストの浅いコピーを作成しますが、ネストされたオブジェクト(たとえば、リスト内のリスト)は依然として同じままです。フラットなリストの場合はこれで十分ですが、ネストされた構造の場合はそうではありません。
例:
lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — ネストされた要素が両方の「コピー」で変更されました
すべてのコレクションに対して.copy()は同じように機能しますか?
いいえ。たとえば、dict.copy()は浅いコピーとして機能し、list.copy()はPython 3.3から登場しました。setにはset.copy()があります。ユーザー定義のオブジェクトの場合、.copy()のサポートは実装されたメソッドによります。
どこでもdeepcopyを使うことはできますか?安全で効率的ですか?
いいえ。deepcopyは高価な操作です:大きな構造物に対してはパフォーマンスの問題を引き起こす可能性があり、コピーできないオブジェクトやクロージャー、非標準オブジェクトで壊れることもあります。完全に独立した再帰コピーが本当に必要な場合にのみdeepcopyを使用してください。
テストでは「辞書の辞書」をdict.copy()を通じてコピーしました。このため、あるユーザーのネストされた構造での修正が突然他のテストに影響を与え(データがグローバルにミュータされました)。
メリット:
デメリット:
copy.deepcopy()を導入し、各オブジェクトのネストレベルと構造の特徴をドキュメントに記述し、部分的な「手動」コピーが可能な大きなボリュームではdeepcopyを避けました。
メリット:
デメリット: