얕은 복사(shallow copy)는 상위 수준의 새 객체를 생성하지만, 중첩된 객체(리스트의 요소, 중첩된 사전 등)는 원본과 메모리를 공유합니다. 깊은 복사(deep copy)는 모든 수준의 객체를 재귀적으로 복사합니다.
다음과 같이 copy 모듈을 통해 사용할 수 있습니다:
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # original과 shallow 모두 변경됨 print(original) # [[99, 2], [3, 4]] # 이제 deep을 사용해봅시다. original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]
copy.copy(obj): "포장"만 복사함copy.deepcopy(obj): 완전 재귀 복사변경 가능한 객체를 포함하는 튜플을 복사하면 어떻게 될까요?
tuple은 불변하지만 그 요소는 변경 가능할 수 있습니다(예: 리스트). Shallow copy와 deep copy가 다릅니다:
import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # deep copy의 경우: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])
이야기
문서 처리 애플리케이션에서 데이터는 사전 안의 리스트에 저장되었습니다. copy.copy를 사용하여 객체를 복사할 때, 중첩된 요소가 새 객체를 수정할 때 우연히 변경되어 시스템의 다른 부분에서 원본 데이터가 바뀌었습니다! 데이터 손상(data corruption)이 발생했습니다. deepcopy로 교체하여 수정했습니다.
이야기
머신 러닝 프로젝트에서 모델의 하이퍼파라미터를 저장할 때, 기본 할당과 얕은 복사를 통해 구성 리스트를 복사했으며, 그 결과 서로 다른 실험이 서로의 매개변수를 변경했습니다. 중첩 리스트 복사 동작을 진단한 후 버그의 출처를 찾았습니다.
이야기
재무 소프트웨어에서 우연히 열린 파일(handle)을 포함하는 객체에 깊은 복사를 적용하여 TypeError: cannot pickle '_io.TextIOWrapper' object가 발생했습니다. 왜냐하면 copy.deepcopy가 내부적으로 pickle을 사용하기 때문입니다. 이러한 필드를 명시적으로 처리하거나 얕은 복사를 호출하여 수정했습니다.