2023-03-18 14:30:18

파이썬 코딩을 할 때 꼭 알아야 하는 개념이 있습니다. 바로 얕은 복사(shallow copy)와 깊은 복사(deep copy)에 대한 개념입니다. 이 개념을 갖고 있지 않으면 굉장한 실수를 범할 수 있습니다. 파이썬으로 코딩을 하시는 분들 중에 얕은 복사, 깊은 복사라는 단어를 들어보신 적이 없거나 제대로 이해하지 않고 있는 분들은 이 글을 꼭 끝까지 읽어주시기 바랍니다. 

 

바로 실례를 통해 얕은 복사와 깊은 복사가 무엇인지 알아가보도록 하겠습니다. 

 

얕은 복사

다음과 같이 a라는 리스트를 하나 만들고 b라는 변수에 대입을 해보도록 하겠습니다.

 

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

 

이 상황에서 b 리스트의 값을 수정해보겠습니다. 첫번째 요소의 값을 10으로 바꿀 것입니다. 잘 바뀌었죠? 

 

b[0] = 10
print("리스트 b: ", b)

 

 

그런데 이 상황에서 리스트 a를 한번 확인해보겠습니다. 

 

print("리스트 a: ", a)

 

 

놀랍게도 리스트 a도 수정되었습니다. 이 사실을 모르고 계셨던 분들은 '헉' 하실 수 있을 것 같습니다. 이렇게 되는 이유는 b = a 이런 식으로 대입을 한 경우에는 메모리에서 a가 저장되어 있는 주소를 b에게도 공유해주는 형태가 됩니다. 변수 a와 변수 b의 주소를 확인해보면 동일한 것을 알 수 있습니다.

 

print("리스트 a 주소:", id(a))
print("리스트 d 주소:", id(b))

 

 

즉, a와 b는 완전히 같은 데이터를 바라보고 있는 것입니다. 따라서 a를 수정해도 b도 수정되는 것이고, b에 수정을 가해도 a에도 영향이 미치는 것입니다. a와 b가 완전히 독립적으로 만드려면 깊은 복사를 사용해야 합니다. 

 

깊은 복사

그렇다면 깊은 복사는 어떻게 할 수 있을까요? copy() 메소드를 사용하면 됩니다. 

 

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

print("리스트 a: ", a)
print("리스트 b: ", b)

print("리스트 a 주소:", id(a))
print("리스트 d 주소:", id(b))

 

 

a = b로 얕은 복사를 시전했을 때와는 달리 리스트 a와 b의 주소가 다른 것을 확인하실 수 있습니다. 이제 b를 수정해보겠습니다.

 

b[0] = 10
print("리스트 a: ", a)
print("리스트 b: ", b)

 

 

이제 b를 수정한 결과가 a에 영향을 주지 않습니다. 

 

리스트를 깊은 복사할 수 있는 방법에는 또 한가지가 더 있습니다. 바로 리스트 요소 전체 슬라이싱한 것을 대입해주는 것입니다. 

 

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

print("리스트 a: ", a)
print("리스트 b: ", b)

print("리스트 a 주소:", id(a))
print("리스트 d 주소:", id(b))

b[0] = 10
print("리스트 a: ", a)
print("리스트 b: ", b)

 

 

이렇게 해도 리스트 a와 b의 주소가 다르고, b에 수정을 가한 것이 a에 영향을 미치지 않습니다. 

 

정리하며

오늘 글을 읽으신 분들은 이제 파이썬에서 얕은 복사의 위험성을 아셨을 것입니다. 데이터의 원본을 잘 보존해야 하는 상황이라면 반드시 깊은 복사를 사용해서 불상사가 펼쳐지지 않길 바랍니다. 리스트 뿐만 아니라 딕셔너리 객체, numpy 배열 객체, pandas 데이터프레임 객체 등에서 같은 원리로 파이썬은 작동하기 때문에 꼭 얕은 복사와 깊은 복사의 차이점을 잘 이해하시고 코드를 짜시기 바랍니다.