2019.03.23 TIL

(TIL은 스스로 이해한 것을 바탕으로 정리한 것으로 오류가 있을 수 있습니다)

# 질문에 답하기.

  1. 단순 객체 복사/ 얕은 복사 / 깊은 복사에 대해 설명하기
  2. 단순 객체 복사/ 얕은 복사 / 깊은 복사 만드는 방법

코드를 통해 알아보는 복사

단순 객체 복사

>>>    #단순 객체 복사
>>>    li = [1,2,3,4]
>>>    li2 = li1
>>>    li2   #[1,2,3,4]
>>>    li2.append(5)    
>>>    li2   #[1,2,3,4,5]
>>>    li   #[1,2,3,4,5]
>>>

li라는 변수는 [1,2,3,4]라는 메모리에 올라온 객체를 가르키고 있다.
li2 = li을 통해 li2는 li의 변수를 복사해온다.
따라서 li2와 li은 같은 객체를 가르키고 있으므로 li2와 li1 가르키는 객체는 완벽하게 동일하다. 따라서 li2를 통해 변경을 하게 되면 li 객체 역시 완벽하게 변경된다.

얕은 복사

>>>    #얕은 복사
>>>    li = [1,2,3,4]
>>>    li3 = li.copy() # or copy.copy(li)도 가능
>>>    li3     #[1,2,3,4]
>>>    li3.append(5)
>>>    li3      #[1,2,3,4,5]
>>>    li       #[1,2,3,4]
>>>

위의 내용을 이해하기 위해서는 단순히 객체가 [1,2,3,4]의 형태처럼 메모리에 올라가 있다고 생각하면 안된다.
실제적으로 파이썬에서 list를 생성한다고 하더라도 모두 모여서 메모리에 올라가지 않는다. [* , * , * , * ]와 같은 형태로 생성되어 첫번째 * 은 1을 가르키고 두 번째 * 은 2를 가르키고 이런 형식이다. 얕은 복사는 [* , * , * , * ]를 복사해 온 것이다. 따라서 li3는 li의 [* , * , * , * ]를 복사해온 것이다. 따라서 li3에서 append를 통해 새로운 요소를 추가하게 되면 li3의 [* , * , * , * ]가 [* , * , * , * , * ]가 되어서 마지막 * 가 새로운 요소를 가르키게 된다. 따라서 li3가 변경되더라도 li는 변경되지 않는다.
하지만 여기에서도 예외는 있다.

>>>    #얕은 복사
>>>    li = [1,2,3,[4,5]]
>>>    li3 = li.copy()
>>>    li3    #[1,2,3,[4,5]]
>>>    li3[3].append(6)
>>>    li3    # [1,2,3,[4,5,6]]
>>>    li     # [1,2,3,[4,5,6]]
>>>

위에서 보면 알 수 있듯이 원래 얕은 복사에서라면 li3를 바꾼다고 해서 li가 바뀌어서는 안된다. 하지만 li는 변경되었다. 그렇다면 li3는 왜 변경되었을까? 위에 언급한대로 li3는 li의 [* , * , * , * ]를 복사해 온 것이다. 위에 예시에서 마지막 * 은 3번째 인덱스 [4,5]을 가르키고 있다. li3와 li 모두 [4,5]을 가르키고 있는 것이다. 따라서 li3를 통해 [4,5]를 변경하게 되면 마지막 *가 가르키는 것이 변경되는 것이므로 li 역시 변경되게 된다.(즉 li와 li3의 내부리스트는 각은 객체를 참조하기 떄문이다.)

이러한 것을 맡기 위해서는 깊은 복사가 필요하다.

깊은 복사

>>>    import copy     #deepcopy를 위해서는 copy를 import 해주어야 한다.
>>>    li = [1,2,3,4]
>>>    li4 = copy.deepcopy(li)
>>>    li4        # [1,2,3,4]
>>>    li4.append(5)
>>>    li4        # [1,2,3,4,5]
>>>    li         # [1,2,3,4]
>>>    li = [1,2,3,[4,5]]
>>>    li4 = copy.deepcopy(li)
>>>    li4        # [1,2,3,[4,5]]
>>>    li4[3].append(6)
>>>    li4        # [1,2,3,[4,5,6]]
>>>    li         # [1,2,3,[4,5]]

깊은 복사를 통해서는 완전히 동일한 새로운 객체를 생성하는 것이므로 li4에 어떤 요소를 추가해도 li는 전혀 영향을 받지 않는다. 따라서 상황에 맡게 단순 객체 복사, 얕은 복사, 깊은 복사를 사용해야 한다.

+ Recent posts