목록을 딥 카피하는 방법?


150

List 사본에 문제가 있습니다.

그래서 E0로부터 전화를 받으면을 호출 'get_edge'하여 사본을 만듭니다 . 여기 추측 의 딥 카피 , 나는 통과 로 . 그러나 주요 기능에서. for 루프 이전 의 결과가 for 루프 이후 의 결과와 다른 이유는 무엇 입니까?E0'E0_copy = list(E0)'E0_copyE0E0_copy'karger(E)'
'print E0[1:10]'

아래는 내 코드입니다.

def get_graph():
    f=open('kargerMinCut.txt')
    G={}
    for line in f:
        ints = [int(x) for x in line.split()]
        G[ints[0]]=ints[1:len(ints)]
    return G

def get_edge(G):
    E=[]
    for i in range(1,201):
        for v in G[i]:
            if v>i:
                E.append([i,v])
    print id(E)
    return E

def karger(E):
    import random
    count=200 
    while 1:
        if count == 2:
            break
        edge = random.randint(0,len(E)-1)
        v0=E[edge][0]
        v1=E[edge][1]                   
        E.pop(edge)
        if v0 != v1:
            count -= 1
            i=0
            while 1:
                if i == len(E):
                    break
                if E[i][0] == v1:
                    E[i][0] = v0
                if E[i][1] == v1:
                    E[i][1] = v0
                if E[i][0] == E[i][1]:
                    E.pop(i)
                    i-=1
                i+=1

    mincut=len(E)
    return mincut


if __name__=="__main__":
    import copy
    G = get_graph()
    results=[]
    E0 = get_edge(G)
    print E0[1:10]               ## this result is not equal to print2
    for k in range(1,5):
        E0_copy=list(E0)         ## I guess here E0_coypy is a deep copy of E0
        results.append(karger(E0_copy))
       #print "the result is %d" %min(results)
    print E0[1:10]               ## this is print2

2
또한 b = a [:]는 얕은 복사본입니다. 참조 stackoverflow.com/questions/16270374/...
아빈 하란

답변:


231

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]]

3
감사합니다. 그러나 list ()는 id (E0)가 id (E0_copy)와 같지 않기 때문에 깊은 사본이라고 생각했습니다. 왜 그런 일이 생길 수 있습니까?
Shen

15
list (...)는 내부 객체를 재귀 적으로 복사하지 않습니다. 내부 변수를 계속 참조하면서 가장 바깥 쪽 목록 만 복사하므로 내부 목록을 변경하면 변경 내용이 원본 목록과 단순 복사본에 모두 반영됩니다.
Sukrit Kalra

1
얕은 복사는 id (a [0]) == id (b [0])를 확인하여 내부 목록을 참조 함을 알 수 있습니다. 여기서 b = list (a)이고 a는 목록의 목록입니다.
Sukrit Kalra

list1.append (리스트 2)는 또한리스트 2의 얕은 사본 인
Lazik

60

많은 프로그래머들이 하나 또는 두 개의 인터뷰 문제를 겪어 링크 목록을 딥 카피해야한다고 생각하지만이 문제는 생각보다 어렵습니다!

파이썬에는 두 가지 유용한 기능을 가진 "복사"라는 모듈이 있습니다

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

주어진 인수가 복합 데이터 구조 (예 : list ) 인 경우 copy ()는 얕은 복사 함수입니다. 파이썬은 동일한 유형 (이 경우 새 목록 )의 다른 객체를 만들지 만 이전 목록의 모든 것에 대해 참조 만 복사됩니다

# think of it like
newList = [elem for elem in oldlist]

직관적으로, 우리는 deepcopy ()가 동일한 패러다임을 따를 것이라고 가정 할 수 있으며, 유일한 차이점은 각 요소 마다 재귀 적으로 deepcopy를 호출 한다는 것입니다 (mbcoder의 답변과 동일).

그러나 이것은 잘못입니다!

deepcopy ()는 실제로 원래 복합 데이터의 그래픽 구조를 유지합니다.

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

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

이것은 딥 카피 () 프로세스 중에 해시 테이블 (python의 사전)을 사용하여 "old_object ref를 new_object ref에 매핑"하는 데 사용됩니다. 이는 불필요한 중복을 방지하여 복사 된 복합 데이터의 구조를 보존합니다.

공식 문서


18

목록의 내용이 기본 데이터 유형 인 경우 이해를 사용할 수 있습니다

new_list = [i for i in old_list]

다음과 같이 다차원 목록에 중첩시킬 수 있습니다.

new_grid = [[i for i in row] for row in grid]

5

귀하의 경우 list elements입니다 immutable objects당신은 그렇지 않으면 사용해야합니다, 이것을 사용할 수 있습니다 deepcopy에서 copy모듈.

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]

21
이것은 딥 카피가 아닙니다.
Sukrit Kalra

1
그럼 뭐야? 그것은 동일한 값을 가진 두 개의 다른 사전을 가지고 있습니다 (각각의 ID를 확인할 수 있습니다).
tailor_raj

이것을 읽으십시오 . [:]는 단지 얕은 복사본을 만들고, 그 안에 개체의 복사본을 재귀 적으로 만들지 않습니다.
Sukrit Kalra

1
감사. 우리가 이것을 사용하면 새 목록이 생성되지만 새 목록의 모든 요소는 사본 일뿐이며 이전 개체와 동일한 객체 (동일한 ID)를 갖게됩니다.
tailor_raj

중첩 된 목록을 사용해보십시오. 목록의 중첩 된 항목 업데이트 a. 목록 b에서도 업데이트됩니다. 이것은 a [:]가 딥 카피가 아님을 의미합니다.
AnupamChugh

2

재귀 딥 카피 기능.

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

편집 : Cfreak이 언급했듯이 이것은 이미 copy모듈 에서 구현되었습니다 .


4
모듈 deepcopy()에서 표준 기능 을 다시 구현할 이유가 없습니다copy
Cfreak

1

목록을 트리로 사용하면 Python의 deep_copy는 다음과 같이 가장 간결하게 작성할 수 있습니다.

def deep_copy(x):
    if not isinstance(x, list): return x
    else: return map(deep_copy, x)

0

다음은 목록을 딥 카피하는 방법의 예입니다.

  b = [x[:] for x in a]

0

이건 더 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.

참고 : 이것은 참조 된 개체 목록으로 안전하지 않습니다


2
작동하지 않습니다. 나는 그것이 단지 체크 된 것이라고 생각했다. 좋은 예로서 사전의 목록을보십시오
Shashank 싱

@ShashankSingh yes 항목이 참조 태그 (메모리 위치를 가리킴)이기 때문에 사전 목록에는 작동하지 않습니다. 따라서이 방법으로 사전 목록을 복제하면 새 목록이 생성되지만 항목은 사전이므로 여전히 동일한 메모리 위치를 참조합니다.
Kwaw Annor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.