2013-09-28 14 views
9

official Python docsは、スライス演算子を使用してPythonで代入すると、スライスされたリストの浅いコピーが作成されます。スライシング操作で深くまたは浅いコピーが得られますか?

しかし、私は例のコード書くとき:

o = [1, 2, 4, 5] 
p = o[:] 

そして、私が書く:

id(o) 
id(p) 

を私は別のIDを取得し、また、1つのリストを追加すると、他のリストには反映されません。それは深いコピーを作成していないか、どこかに間違っていますか?

答えて

14

浅いコピーを作成しています。これは、ネストされた値がコピーされず、単に参照されるためです。 深いコピーは、リストによって参照される値のコピーも作成します。

デモ:

>>> lst = [{}] 
>>> lst_copy = lst[:] 
>>> lst_copy[0]['foo'] = 'bar' 
>>> lst_copy.append(42) 
>>> lst 
[{'foo': 'bar'}] 
>>> id(lst) == id(lst_copy) 
False 
>>> id(lst[0]) == id(lst_copy[0]) 
True 
ここ

ネストされた辞書はコピーされません。両方のリストによって参照されるだけです。新しい要素42は共有されません。

Pythonのすべてがオブジェクトであり、名前とリスト要素はそれらのオブジェクトへの参照に過ぎないことに注意してください。リストのコピーは新しい外側リストを作成しますが、新しいリストは全く同じオブジェクトへの参照を受け取るだけです。

適切なディープコピーが再帰的に、リストに含まれる各およびすべてのオブジェクトの新しいコピーを作成します。

>>> from copy import deepcopy 
>>> lst_deepcopy = deepcopy(lst) 
>>> id(lst_deepcopy[0]) == id(lst[0]) 
False 
+0

なぜ私は異なるIDを取得しているのですか? – user2528042

+1

@ user2528042:*外部リストオブジェクト*は同じではないためです。 –

+0

@ user2528042元のリスト*が新しいオブジェクトにコピーされる*ため。内のすべての要素がコピーされないので、リストに変更可能なオブジェクトが含まれていれば(intsは変更不可能です)、そのオブジェクトを変更すると、元のオブジェクトとコピーされたリストの両方が同じオブジェクトへの参照のコピーを持つため変更されます。 – poke

5

あなたはisまたはidを使用してテストが真のコピーが行われているかどうかの誤解を招くことができることを知っている必要がありimmutablesを含む文字列、整数、タプルなどのオブジェクトは不変でinternedです。

簡単インターン文字列の例を理解して考えてみましょう:

>>> l1=['one'] 
>>> l2=['one'] 
>>> l1 is l2 
False 
>>> l1[0] is l2[0] 
True 

は今l1の簡易コピーを作成し、不変の文字列をテストします。

>>> l3=l1[:] 
>>> l3 is l1 
False 
>>> l3[0] is l1[0] 
True 

今すぐl1[0]に含まれる文字列のコピーを作成:

>>> s1=l1[0][:] 
>>> s1 
'one' 
>>> s1 is l1[0] is l2[0] is l3[0] 
True    # they are all the same object 

T RYすべての要素をコピーする必要がありますdeepcopy:(彼らは同じidを持っている)いずれの場合においても

>>> from copy import deepcopy 
>>> l4=deepcopy(l1) 
>>> l4[0] is l1[0] 
True 

は、文字列'one'は不変の文字列のPythonの内部キャッシュに抑留されているとisは、それらが同じであることが表示されます。これは、実装されているものと実行されたときの実装とバージョンに依存するため、依存することはできません。これは、メモリとパフォーマンスを大幅に向上させることができます。

あなたは即座に抑留されない例に強制することができます

>>> s2=''.join(c for c in 'one') 
>>> s2==l1[0] 
True 
>>> s2 is l1[0] 
False 

をそしてあなたが見つかった場合、その文字列がキャッシュされたオブジェクトを参照させるためにはPython intern functionを使用することができます。

>>> l1[0] is s2 
False 
>>> s2=intern(s2) 
>>> l1[0] is s2 
True 
同じ

immutablesのタプルに適用されます。

>>> t1=('one','two') 
>>> t2=t1[:] 
>>> t1 is t2 
True 
>>> t3=deepcopy(t1) 
>>> t3 is t2 is t1 
True 

アン(整数のような)immutablesのD変更可能なリストは、リストのメンバーが埋葬持つことができます。

>>> li1=[1,2,3] 
>>> li2=deepcopy(li1) 
>>> li2 == li1 
True 
>>> li2 is li1 
False 
>>> li1[0] is li2[0] 
True 

ですから、あなたが知っているPythonのオペレーションを使用することが最終的な結果が、何かをコピーしますインターン不変オブジェクトへの別の参照です。 isテストは、アイテムが変更可能な場合に作成されるコピーの慎重なテストにすぎません。

+0

Python 3では、 'intern'が' sys'モジュールに移動されていますので、 'import sys; s = sys.intern(s) ' – dawg

関連する問題