Python의 할당 대 얕은 복사 대 깊은 복사

This article was originally shared on my blog.



오늘은 Python에서 복사하는 방법에 대해 알아보겠습니다. 세 가지 방법이 있습니다. 이 문서에서는 각 작업이 수행하는 작업과 작업이 어떻게 다른지 알게 됩니다.

1 - 할당 연산자(=)2 - 얕은 사본
3 - 딥 카피

할당 연산자(=)



>>> a = [1, 2, 3, 4, 5]
>>> b = a

위의 대입 연산자 예에서 Python 개체의 복사본을 만들지 않고 메모리 주소(또는 포인터)를 a에서 b , (b=a)로 복사합니다. 이는 ab가 모두 동일한 메모리 주소를 가리키고 있음을 의미합니다.

여기서 우리는 id() 메서드를 사용하여 메모리에 있는 객체의 주소를 가져오고 두 목록이 동일한 메모리를 가리키는지 확인할 수 있습니다.

>>> id(a) == id(b)
True

>>> print('id of a - {}, id of b - {}'.format(id(a), id(b)))
id of a - 140665942562048, id of b - 140665942562048


따라서 여기에서 새 목록을 편집하면 원래 목록에서도 업데이트됩니다.

>>> b.append(6)
>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]

메모리에 해당 목록의 인스턴스가 하나만 있기 때문입니다.

얕은 카피



얕은 복사는 새로운 복합 객체를 구성한 다음 (가능한 한) 원본에서 찾은 객체에 대한 참조를 여기에 삽입합니다.

얕은 사본을 만드는 3가지 방법이 있습니다.

nums = [1, 2, 3, 4, 5]      

>>> import copy

>>> m1 = copy.copy(nums)       # make a shallow copy by using copy module
>>> m2 = list(nums)    # make a shallow copy by using the factory function
>>> m3 = nums[:]       # make a shallow copy by using the slice operator

위의 모든 목록에는 원래 목록과 동일한 값이 포함되어 있습니다.

>>> print(nums == m1 == m2 == m3)
True

그러나 각각의 메모리 주소는 다릅니다.

>>> print('nums_id - {}, m1_id - {}, m2_id - {}, m3_id = {}'.format(id(nums), id(m1), id(m2), id(m3)))
nums_id - 140665942650624, m1_id - 140665942758976, m2_id - 140665942759056, m3_id = 140665942692000

즉, 이번에는 각 목록의 객체가 고유한 독립 메모리 주소를 가집니다.

이제 더 흥미로운 부분으로 이동하십시오. 원래 목록이 복합 객체(예: 목록 목록)인 경우 얕은 복사 후에도 새 목록 요소는 여전히 원래 요소를 참조합니다.
따라서 목록과 같은 변경 가능한 요소를 수정하면 변경 사항이 원래 요소에 반영됩니다. 더 나은 이해를 위해 아래 예를 살펴보겠습니다.

>>> import copy

>>> a = [[1, 2], [3, 4]]            
>>> b = copy.copy(a)

>>> id(a) == id(b)
False

>>> b[0].append(5)
>>>
>>> b
[[1, 2, 5], [3, 4]]
>>> a
[[1, 2, 5], [3, 4]]      # changes reflected in original list also


위의 예에서 볼 수 있듯이 새 목록에서 내부 목록 요소를 수정하는 동안 원래 목록에서도 업데이트됩니다. 왜냐하면 a[0]b[0]가 여전히 동일한 메모리 주소(원래 목록)를 가리키고 있기 때문입니다.

>>> print('a[0] - {} , b[0] - {}'.format(id(a[0]), id(b[0])))       
a[0] - 140399422977280 , b[0] - 140399422977280
>>>

>>> id(a[0]) == id(b[0])
True
>>> id(a[1]) == id(b[1])
True

따라서 새 목록b에는 자체 메모리 주소가 있지만 요소에는 없습니다. 목록의 요소를 새 개체에 복사하는 대신 얕은 복사에서 메모리 주소에 대한 참조를 복사하기 때문에 원본 개체를 변경하는 동안 복사된 개체에 반영되고 그 반대도 마찬가지입니다.

이것은 얕은 복사의 특징입니다.

딥 카피



전체 복사는 새 복합 개체를 구성한 다음 원본에서 찾은 개체의 복사본을 여기에 재귀적으로 삽입합니다.

모든 항목에 대해 새 복사본을 만들기 때문에 깊은 복사본을 만드는 속도가 느립니다. 이것은 단순히 복합 객체의 주소를 복사하는 것이 아니라 원래 목록의 모든 목록 요소(단순 및 복합 객체)의 전체 복사본을 만들고 새 목록에 대해 다른 메모리 주소를 할당한 다음 복사된 요소를 할당합니다. .

깊은 복사를 달성하려면 copy 모듈을 가져와야 합니다. 그리고 copy.deepcopy()를 사용합니다.

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]  
>>> b = copy.deepcopy(a)                     

>>> id(a) == id(b)
False

>>> id(a[0]) == id(b[0])      # memory address is different      
False

>>> a[0].append(8)            # modify the list                                                                                                                                            


>>> a
[[1, 2, 3, 8], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]        # New list’s elements didn’t get affected

위에서 볼 수 있듯이 원래 목록은 영향을 받지 않습니다.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances).



할당 연산자, Shallow Copy 및 Deep Copy에 대한 설명이 마음에 드셨으면 합니다. 그래도 Copy in Python과 관련하여 의심이나 개선 사항이 있으면 의견 섹션에서 질문하십시오.

참조:
https://docs.python.org/2/library/copy.html

좋은 웹페이지 즐겨찾기