list.copy()는 바깥 리스트만 새로 만들고 안의 객체는 공유하는 얕은 복사다. 복사한 리스트 안의 중첩 값을 바꾸면 원본에서도 보일 수 있다. other = original은 바깥 리스트조차 복사하지 않는 할당이고, 중첩 객체도 복사해야 할 때는 copy.deepcopy의 계약을 확인한다.
복사했는데 원본도 바뀌는 최소 예제
original = [["초안"]]
copied = original.copy()
copied[0].append("수정")
print(original)
print(copied is original)
print(copied[0] is original[0])
[['초안', '수정']]
False
True
두 바깥 리스트는 다르지만, 0번 칸은 같은 안쪽 리스트를 가리킨다. copied[0].append는 그 공유 객체를 바꿨다. 이 예제에서 확인할 것은 출력 값뿐 아니라 is로 확인한 객체의 동일성이다.
각 Python 코드 블록은 import와 입력을 포함한 독립 예제다. CPython 3.14.3·Windows 11에서 실행했고 Python 3.14 공식 문서와 대조했다. 문서 사이트의 패치 판본은 실행한 인터프리터와 다를 수 있다.
할당·얕은 복사·깊은 복사를 나란히 확인하기
from copy import deepcopy
original = [{"labels": ["초안"]}]
assigned = original
shallow = original.copy()
deep = deepcopy(original)
print("assigned:", assigned is original)
print("shallow:", shallow is original, shallow[0] is original[0])
print("deep:", deep is original, deep[0] is original[0])
shallow.append({"labels": ["별도"]})
shallow[0]["labels"].append("수정")
print("lengths:", len(original), len(shallow))
print("original:", original)
print("deep:", deep)
assigned: True
shallow: False True
deep: False False
lengths: 1 2
original: [{'labels': ['초안', '수정']}]
deep: [{'labels': ['초안']}]
shallow에 항목을 추가한 일은 새 바깥 리스트만 바꿔 길이가 2가 됐다. 반면 공유한 사전 안의 labels 리스트를 수정한 일은 original에도 보인다. 이 예제의 deep은 그 사전과 안쪽 리스트도 복사해 원본 수정과 분리됐다.
| 하려는 일 | 선택 | 확인할 점 |
|---|---|---|
| 같은 리스트를 다른 이름으로 사용 | 할당 | 추가·삭제도 같은 객체에 반영 |
| 바깥 리스트의 순서·항목만 따로 변경 | 얕은 복사 | 안쪽 객체는 공유 |
| 중첩된 변경 가능한 객체도 복사 | deepcopy 검토 | 내부 공유 관계와 객체별 지원 확인 |
copy 공식 문서는 할당이 객체를 복사하지 않는다는 점과 두 복사의 차이를 설명한다. list의 슬라이스 original[:]나 list(original)로 바깥 리스트를 새로 만들어도 중첩 객체까지 자동 복사하는 것은 아니다.
깊은 복사도 내부의 공유 관계를 없애지는 않는다
from copy import deepcopy
shared = ["원본"]
original = [shared, shared]
cloned = deepcopy(original)
print(cloned[0] is original[0])
print(cloned[0] is cloned[1])
cloned[0].append("복사본 수정")
print(original)
print(cloned)
False
True
[['원본'], ['원본']]
[['원본', '복사본 수정'], ['원본', '복사본 수정']]
원본에서 두 칸이 하나의 리스트를 공유했다. 깊은 복사에서는 새 안쪽 리스트가 생겼지만 복사본의 두 칸도 그 새 리스트를 함께 참조한다. deepcopy는 memo를 사용해 이미 복사한 객체를 기억한다. 모든 등장 위치에 서로 독립적인 객체를 만드는 연산이라고 해석하면 안 된다.
파일·소켓 같은 자원을 일반 리스트처럼 복제할 수 있다고 가정하지 않는다. 함수·클래스처럼 그대로 반환되는 객체도 있고, 사용자 정의 클래스는 복사 동작을 정할 수 있다. 필요한 필드만 분리하면 되는지, 공유가 의도된 것인지부터 판단한다. 이 글의 리스트·사전·문자열 예제가 임의의 외부 자원이나 사용자 정의 객체의 복사를 검증한 것은 아니다.
“리스트를 복사했는데 원본도 바뀔 때: 얕은 복사와 deepcopy”에 대한 2개의 생각