221

の後、は と等しくないため、 のディープ コピーE0_copy = list(E0)だと思います。次に、ループで変更しますが、後で同じにならないのはなぜですか?E0_copyE0id(E0)id(E0_copy)E0_copyE0

E0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for k in range(3):
    E0_copy = list(E0)
    E0_copy[k][k] = 0
    #print(E0_copy)
print E0  # -> [[0, 2, 3], [4, 0, 6], [7, 8, 0]]
4

10 に答える 10

320

E0_copyディープコピーではありません。を使用してディープ コピーを作成することはありませんlist()。( と は両方ともlist(...)浅いtestList[:]コピーです。)

copy.deepcopy(...)リストのディープコピーに使用します。

deepcopy(x, memo=None, _nil=[])
    Deep copy operation on arbitrary Python objects.

次のスニペットを参照してください -

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b   # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]

deepcopy操作を参照してください

>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b    # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]

説明するためlist(...)に、内部オブジェクトのコピーを再帰的に作成しません。同じ内部リストを参照しながら、最も外側のリストのコピーのみを作成するため、内部リストを変更すると、変更は元のリストと浅いコピーの両方に反映されます。id(a[0]) == id(b[0])whereを確認すると、浅いコピーが内部リストを参照していることがわかりますb = list(a)

于 2013-07-26T05:13:22.267 に答える
85

多くのプログラマーは、リンクされたリストをディープ コピーするように求められる面接の問題に遭遇したことがあると思いますが、この問題は思ったよりも難しいものです。

Python には、次のcopy2 つの便利な関数で呼び出されるモジュールがあります。

import copy
copy.copy()
copy.deepcopy()

copy()シャローコピー機能です。指定された引数がlistなどの複合データ構造である場合、Python は同じ型の別のオブジェクト (この場合は新しい list ) を作成しますが、古いリスト内のすべてのものについては、それらの参照のみがコピーされます。次のように考えてください。

newList = [elem for elem in oldlist]

deepcopy()直感的に、同じパラダイムに従うと仮定できます。唯一の違いは、各elem に対して deepcopy を再帰的に呼び出すことです( mbguy の answerと同様) 。

しかし、これは間違っています!

deepcopy()元の化合物データのグラフィック構造を実際に保持します。

a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)

# check the result
c[0] is a # False, a new object a_1 is created
c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]

これは注意が必要な部分です。 の処理中にdeepcopy()、ハッシュテーブル (Python では辞書) を使用して、古い各オブジェクト ref を新しい各オブジェクト ref にマップします。これにより、不要な重複が防止され、コピーされた複合データの構造が保持されます。

公式ドキュメント

于 2015-09-25T22:33:52.020 に答える
8

リスト要素が不変オブジェクトの場合はこれを使用できますが、それ以外の場合はdeepcopyfromcopyモジュールを使用する必要があります。

このようなディープコピーに最短の方法を使用することもできますlist

a = [0,1,2,3,4,5,6,7,8,9,10]
b = a[:] #deep copying the list a and assigning it to b
print id(a)
20983280
print id(b)
12967208

a[2] = 20
print a
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10]
print b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10]
于 2013-07-26T06:22:24.740 に答える
-1

単なる再帰的なディープ コピー関数です。

def deepcopy(A):
    rt = []
    for elem in A:
        if isinstance(elem,list):
            rt.append(deepcopy(elem))
        else:
            rt.append(elem)
    return rt

編集: Cfreak が述べたように、これは既にcopyモジュールに実装されています。

于 2013-07-26T06:33:38.073 に答える
-1

リストをツリーとして考えると、Python の deep_copy は次のように最もコンパクトに記述できます。

def deep_copy(x):
    if not isinstance(x, list):
        return x
    else:
        return [deep_copy(elem) for elem in x]

基本的には、深さ優先の方法でリストを再帰的に走査しています。

于 2013-12-13T18:08:30.360 に答える
-3

これはよりpythonicです

my_list = [0, 1, 2, 3, 4, 5]  # some list
my_list_copy = list(my_list)  # my_list_copy and my_list does not share reference now.

注: これは、参照されたオブジェクトのリストでは安全ではありません

于 2016-11-29T14:55:02.217 に答える