질문 역사: Python에서 객체 복사(특히 컬렉션 - 목록, 사전)는 중요하다. 단순히 변수를 할당하는 것은 복사가 아닌 새로운 참조를 만든다. 불필요한 "부작용"을 방지하기 위해 copy()와 deepcopy()와 같은 특수 메소드가 도입되었다.
문제: 중첩된 컬렉션(목록 안의 목록, 사전 안의 사전) 작업 시, 단순 copy()는 컨테이너만 복사할 뿐 내부 요소는 복사하지 않는다. 이는 수정된 중첩 요소가 모든 "복사본"에 반영되는 어려운 버그를 일으킬 수 있다.
해결책: copy.copy()는 얕은 복사(shallow copy)를 생성하여 상위 수준의 새로운 컨테이너를 만들지만 중첩된 객체는 동일하게 남는다. copy.deepcopy()는 모든 중첩된 객체를 재귀적으로 복사한다.
코드 예제:
import copy lst = [[1, 2], [3, 4]] shallow = copy.copy(lst) deep = copy.deepcopy(lst) lst[0][0] = 10 print(shallow) # [[10, 2], [3, 4]] — 중첩 객체가 변경됨! print(deep) # [[1, 2], [3, 4]] — deepcopy가 원래 상태를 유지함
핵심 특징:
목록 복사를 위해 lst2 = lst[:]라고 작성하는 것이 충분한가요?
lst2 = lst[:]는 목록의 얕은 복사를 생성하지만 중첩된 객체(예: 목록 내의 목록)는 여전히 동일하다. 평면 목록의 경우 충분하지만 중첩 구조에는 그렇지 않다.
예시:
lst = [[1], [2]] lst2 = lst[:] lst[0][0] = 99 print(lst2) # [[99], [2]] — 중첩 요소가 두 "복사본" 모두에서 변경됨
모든 컬렉션에 대해 .copy() 메소드가 동일하게 작동하나요?
아니요. 예를 들어, dict.copy()는 얕은 복사를 수행하고, list.copy()는 Python 3.3부터 등장했으며, set의 경우에는 set.copy()가 있다. 사용자 정의 객체의 경우 .copy()의 지원은 구현된 메소드에 따라 다르다.
모든 곳에서 deepcopy로 대체할 수 있나요? 안전하고 효율적인가요?
아니요. deepcopy는 비싼 연산이다: 대규모 구조에서 성능 문제를 일으킬 수 있으며, 복사할 수 없는/클로저 혹은 비표준 객체에서는 작동하지 않는다. 완전히 독립적이고 재귀적인 복사가 정말로 필요할 때만 deepcopy를 사용해야 한다.
테스트에서 "사전의 사전"을 dict.copy()를 통해 복사했다. 이로 인해 한 사용자의 중첩 구조에서의 수정이 다른 테스트에도 갑작스럽게 영향을 미쳤다(데이터가 전역적으로 변형됨).
장점:
단점:
copy.deepcopy()를 도입하고, 각 객체의 중첩 수준과 구조의 특징을 문서화했으며, 큰 데이터에서는 "수동"으로 부분적으로 복사하는 것을 피했다.
장점:
단점: