copy — 얕은 복사와 깊은 복사 연산

copy — 얕은 복사와 깊은 복사 연산

copy 모듈은 객체를 얕은 복사(shallow copy)하거나 깊은 복사(deep copy)하는 함수를 제공해요. 파이썬에서 객체가 참조로 전달되는 특성 때문에, 복사본을 안전하게 만들 필요가 있을 때 이 모듈이 유용합니다.

출처: Python 표준 라이브러리

본문

얕은 복사

copy.copy(x)x의 얕은 복사본을 반환해요. 얕은 복사는 객체 자체는 새로 만들지만, 객체가 참조하는 내부 요소들은 새로 복사하지 않고 그대로 공유합니다. 즉 최상위 객체는 복사되고 그 안의 항목(리스트 요소나 딕셔너리 값 등)은 원본과 같은 객체를 가리키게 돼요.

깊은 복사

copy.deepcopy(x[, memo])x의 깊은 복사본을 반환해요. 깊은 복사는 객체와 그 객체가 참조하는 모든 내부 구조를 재귀적으로 새로 만들어, 원본과 완전히 독립된 복사본을 생성합니다. memo는 이전에 복사된 객체를 기억하는 딕셔너리로, 순환 참조가 있는 객체를 복사할 때 무한 재귀를 막는 데 쓰입니다.

import copy

a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)   # 완전히 독립된 복사본
b[0][0] = 99
print(a)   # [[1, 2], [3, 4]]  — 원본은 영향 없음

기타 함수와 주의

copy.replace(x, /, **changes) — 객체를 새로 만들지 않고 특정 속성·키를 바꾼 복사본을 만드는 데 도움을 주는 함수예요(버전 3.13에서 추가). 이는 dataclasses.replace()typing.NamedTuple과 유사한 기능을 일반화한 것입니다.

복사 동작은 다음 우선순위로 결정돼요.

  • __copy__() 메서드 — 얕은 복사용. 정의돼 있으면 copy.copy()가 호출합니다.
  • __deepcopy__(memo) 메서드 — 깊은 복사용. 정의돼 있으면 copy.deepcopy()가 호출합니다.
  • 둘 다 없으면 내장 타입에 따라 기본 복사가 진행되는데, 대부분의 타입에서 얕은 복사는 같은 타입의 "생성자 + 요소 채우기" 방식, 깊은 복사는 재귀적으로 요소를 복사하는 방식으로 이뤄져요.

사용자 정의 클래스에서 __copy__()__deepcopy__()를 정의하면 복사 방식을 직접 제어할 수 있어요. 또 모듈, 메서드, 스택 트레이스(frame), 스택 검사용 코드, 파일 객체, 소켓, 윈도우, 배열(array), 정규식 객체 같은 타입은 복사할 수 없거나 특별한 처리 없이는 복사가 의미 없어서, 복사하려 하면 TypeError가 발생할 수 있어요.

참고할 점

클래스가 순환 참조를 가지거나 복잡한 그래프 구조를 가질 때는 깊은 복사에 주의해야 해요. deepcopy()는 이미 만든 복사본을 memo에 기록해 순환을 안전하게 처리하지만, 사용자 정의 복사 로직을 가진 객체에서는 예기치 않은 동작이 있을 수 있습니다. 복사 비용이 크다면 불변(immutable) 객체를 재사용하는 설계가 더 나을 때가 많아요.

더 알아보기