BioPlayground

🧬
목록으로

가변 객체의 참조 전파 — 복사의 함정

Python에서 리스트를 복사했는데 원본이 바뀌는 이유, 얕은 복사와 깊은 복사의 차이, copy 모듈 사용법을 배웁니다.

중급
|
10
|
검증 완료 (2026-07)
가변 객체참조 전파shallow copydeep copymutablelist 복사
진행률0/15 (0%)

가변 객체의 참조 전파 — 복사의 함정

이 토픽을 마치면

Python에서 리스트를 =로 복사하면 왜 원본이 바뀌는지 이해하고, 얕은 복사와 깊은 복사를 구분해서 사용할 수 있습니다.


복사했는데 원본이 바뀐다

python
original = [1, 2, 3]
copy = original
copy.append(4)
print(original) # [1, 2, 3, 4] — 원본도 바뀜!

copy = original복사가 아닙니다. 같은 리스트에 이름표를 하나 더 붙인 것입니다. originalcopy는 같은 리스트를 가리키는 두 개의 이름입니다.

이전 토픽(변수와 메모리)에서 변수는 "값을 담는 상자"가 아니라 "객체를 가리키는 화살표"라고 배웠습니다. 이것이 실전에서 문제를 일으키는 순간이 바로 여기입니다.

python
print(id(original)) # 4392957504
print(id(copy)) # 4392957504 — 같은 주소!

진짜 복사 — 슬라이싱

python
original = [1, 2, 3]
copy = original[:] # 전체 슬라이싱 = 새 리스트
copy.append(4)
print(original) # [1, 2, 3] — 원본 안 바뀜
print(copy) # [1, 2, 3, 4]

[:]는 리스트의 처음부터 끝까지 잘라서 새 리스트를 만듭니다. list(original)이나 original.copy()도 같은 효과입니다.


얕은 복사의 한계

python
matrix = [[1, 2], [3, 4]]
shallow = matrix[:]
shallow[0][0] = 99
print(matrix) # [[99, 2], [3, 4]] — 원본도 바뀜!

슬라이싱은 1단계만 복사합니다. matrix[:]는 바깥 리스트는 새로 만들지만, 안의 [1, 2][3, 4]같은 객체를 공유합니다. 안쪽을 수정하면 원본에도 반영됩니다.

이것이 **얕은 복사(shallow copy)**입니다.


깊은 복사 — copy.deepcopy

python
import copy
matrix = [[1, 2], [3, 4]]
deep = copy.deepcopy(matrix)
deep[0][0] = 99
print(matrix) # [[1, 2], [3, 4]] — 원본 안 바뀜

deepcopy는 내부 객체까지 전부 재귀적으로 복사합니다. 완전히 독립된 새 객체입니다.


언제 뭘 쓸까

상황방법이유
1차원 리스트lst[:] 또는 lst.copy()빠르고 간단
2차원 이상 중첩 리스트copy.deepcopy(lst)내부 리스트까지 독립 필요
딕셔너리dict.copy() 또는 {**d}1단계 얕은 복사
중첩 딕셔너리copy.deepcopy(d)내부 dict/list까지 독립
정말 복사 안 해도 되는 경우= 그대로의도적으로 같은 객체를 공유할 때

함수 인자에서도 똑같이

python
def add_item(lst, item):
lst.append(item)
return lst
my_list = [1, 2, 3]
result = add_item(my_list, 4)
print(my_list) # [1, 2, 3, 4] — 원본이 바뀜

함수에 리스트를 전달하면 참조가 전달됩니다. 함수 안에서 .append()하면 원본도 바뀝니다. 원본을 보존하려면 함수 안에서 복사를 먼저 하세요:

python
def add_item_safe(lst, item):
new_lst = lst[:]
new_lst.append(item)
return new_lst

가변 vs 불변 정리

타입가변/불변= 복사 후 수정 시 원본 영향
int, float, str, tuple불변영향 없음 (어차피 새 객체 생성)
list, dict, set가변원본도 바뀜

불변 객체는 이 문제가 발생하지 않습니다. 문자열을 "수정"하면 항상 새 문자열이 만들어지니까요. 가변 객체에서만 주의가 필요합니다.


핵심

=는 복사가 아니라 같은 객체에 이름을 하나 더 붙이는 것입니다. 1차원은 [:].copy(), 중첩 구조는 copy.deepcopy(). 함수에 가변 객체를 넘기면 원본이 바뀔 수 있습니다 — 의도하지 않았다면 먼저 복사하세요.