본문 바로가기
데이터 사이언스/Python 프로그래밍

얕은복사 깊은복사 참조변수 사본전달 원본전달 shallow copy deep copy

by 윤슬새벽 2025. 6. 18.
반응형

🧠 핵심 비유: 복사는 "노트 복사"다!

  • 📄 얕은 복사: "노트의 표지와 차례를 복사하지만, 안에 낀 포스트잇은 원본과 공유"
  • 📚 깊은 복사: "노트뿐 아니라 안의 포스트잇, 메모지, 첨부자료까지 전부 새로 복사"

📦 구조 예시로 보기

original = [1, 2, [3, 4]]

복사 종류 설명
copy.copy(original) 리스트만 새로 만들고, 내부의 [3, 4]는 공유
copy.deepcopy(original) 리스트도 새로, 내부의 [3, 4]도 새로 복사
 

🔍 차이 정리표


 

항목 얕은 복사 (copy.copy) 깊은 복사 (copy.deepcopy)
복사 대상 가장 바깥쪽 객체만 새로 만듦 모든 내부 객체까지 새로 만듦
내부 변경 영향 원본과 복사본에 모두 영향 복사본만 변경됨
속도 빠름 느림
메모리 사용 적음 많음
사용 시기 내부 객체가 안 바뀔 때 중첩된 객체도 바꾸고 싶을 때
 

✅ 코드 예제로 명확히 보기

import copy

original = [1, 2, [3, 4]]

# 얕은 복사
shallow = copy.copy(original)

# 깊은 복사
deep = copy.deepcopy(original)

# 내부 리스트 변경
original[2][0] = 999

print("원본:", original)     # [1, 2, [999, 4]]
print("얕은 복사:", shallow) # [1, 2, [999, 4]] ← 내부 공유
print("깊은 복사:", deep)    # [1, 2, [3, 4]]   ← 독립 객체

🎯 언제 어떤 걸 써야 할까?

상황 권장 복사 방식
리스트 안에 숫자나 문자열만 있다 얕은 복사로 충분
딕셔너리 안에 리스트가 있고, 그걸 바꾸려 한다 깊은 복사 필요
복사 후 원본과 완전히 분리된 상태에서 작업하고 싶다 깊은 복사 필수
 

🧵 한 줄 요약

얕은 복사는 껍데기만 새로 만들고 안은 공유,
깊은 복사는 안까지 전부 새로 만든다.


 

✅ 정리: 얕은 복사 vs 깊은 복사 핵심 요약

개념 설명
얕은 복사 바깥 객체는 새로 만들지만, 내부 객체는 원본을 참조합니다.
깊은 복사 바깥 객체뿐 아니라 내부 객체까지 전부 새로 복사합니다.
불변 객체 (immutable) int, float, str, tuple 등은 복사해도 참조나 다름없으며, 값을 절대 변경할 수 없음
 

🎯 개념별로 다시 정리해 드리면:

✅ 1. 얕은 복사 = 참조형 내부는 공유

import copy

a = [1, 2, [3, 4]]
b = copy.copy(a)  # 얕은 복사

a[2][0] = 999
print(b)  # [1, 2, [999, 4]]  ← 내부 리스트는 a와 b가 **공유**
  • a와 b는 바깥 리스트는 다르지만, 안의 [3, 4]는 같은 객체를 참조합니다.

✅ 2. 깊은 복사 = 내부까지 전부 새로 만들어서 독립적

c = copy.deepcopy(a)
a[2][0] = 777
print(c)  # [1, 2, [999, 4]] ← 변경 안 됨, 완전히 분리됨

✅ 3. 불변 객체 (immutable) 는 복사든 참조든 차이 없음

x = "hello"
y = x
x = "world"

print(y)  # hello ← 문자열은 값이 바뀌지 않음. 참조라도 상관 없음
  • str, int, tuple 같은 불변 객체는 값을 바꿀 수 없기 때문에, 참조건 복사건 의미 차이가 없습니다.
  • 따라서 얕은 복사와 깊은 복사의 차이는 '가변 객체(mutable)'가 내부에 있을 때만 중요합니다.

🧠 직관적 비유로 마무리

개념 비유
얕은 복사 책 표지를 복사하되, 안에 끼운 부록은 같이 공유
깊은 복사 책 표지와 부록까지 전부 새로 인쇄
불변 객체 돌덩이. 어디에 둬도 변하지 않고 공유해도 안전
 

✅ 핵심 정리 문장

"얕은 복사는 외형만 새로 만들고 내부는 여전히 원본을 참조한다.
깊은 복사는 내부까지 전부 복제한다.
불변 객체는 바뀌지 않으므로 복사나 참조나 결과가 같다."

 


📌 얕은 복사의 2가지 결과

내부 요소의 종류 복사 이후 변경 시 원본 영향 이유
불변 객체 (int, str, tuple) ❌ 없음 값을 바꾸면 새 객체를 만든 것
가변 객체 (list, dict, set) ✅ 있음 같은 객체를 참조하고 있기 때문
 

✅ 1. 불변 객체가 내부에 있을 때: 원본 영향 없음

import copy

a = [1, 2, 3]
b = copy.copy(a)

b[0] = 999  # 인덱스 0에 새 값 할당
print(a)  # [1, 2, 3] → 원본 안 바뀜
  • int는 불변 객체라 새 값을 할당하면 b[0]만 바뀜 (새 객체로 교체됨)
  • 얕은 복사라 해도 불변 객체를 바꾸면 그냥 다른 값을 참조하게 되는 것

✅ 2. 가변 객체가 내부에 있을 때: 원본도 바뀜

a = [1, 2, [3, 4]]
b = copy.copy(a)

b[2][0] = 999
print(a)  # [1, 2, [999, 4]] → 원본도 바뀜
  • 내부의 [3, 4]는 리스트 → 가변 객체
  • 얕은 복사에서는 내부 객체는 동일한 참조이므로, 내부 요소를 바꾸면 원본도 바뀜

📊 핵심 비교 표: 얕은 복사에서 값 변경 시 원본 영향

내부 요소 유형 예시 복사 후 요소 변경 원본 영향 여부 설명
불변 객체 [1, 2, 3] b[0] = 999 ❌ 없음 int는 값만 바뀌고 원본과 무관
가변 객체 [1, 2, [3, 4]] b[2][0] = 999 ✅ 있음 [3, 4]는 원본과 공유됨
 

🧠 추가 팁: 내부 객체가 몇 단계 더 중첩된 경우

a = [[1, 2], [3, 4]]
b = copy.copy(a)

b[0][0] = 100
print(a)  # [[100, 2], [3, 4]] → 역시 변경됨
  • 중첩되어 있어도, 내부 가변 객체는 모두 원본과 공유됨
  • 중첩이 있는 경우에는 **깊은 복사 (copy.deepcopy)**를 써야 완전 분리 가능

✅ 한 줄 핵심

얕은 복사라도 내부에 있는 것이 불변 객체면 영향이 없고, 가변 객체면 원본이 바뀐다.


📌 사본 전달 vs 원본 전달 (참조 변수의 차이)


🎁 비유로 이해하기

개념 설명 비유
사본(copy) 기존 리스트와 똑같지만 완전히 새로운 리스트를 만듦 프린터로 문서를 복사해서 새 종이로 만드는 것
참조(reference) 기존 리스트를 가리키는 또 다른 변수 책상 위의 같은 책을 두 사람이 함께 보는 것
 

🧪 코드와 함께 보기

numbers = list(range(11))        # [0, 1, 2, ..., 10]
 

✅ 1. 슬라이싱을 통한 사본 생성

reversed_list = numbers[::-1]   # ← 새 리스트가 만들어짐
reversed_list[0] = 99
  • reversed_list는 numbers의 복사본
  • reversed_list[0]만 바뀌고, numbers는 변하지 않음

📌 사본이므로 원본과는 완전히 별개


❌ 2. 단순 대입은 참조 공유

numbers2 = numbers
numbers2[0] = 11
  • numbers2는 numbers와 같은 리스트를 함께 가리킴
  • numbers2[0] = 11 하면 → numbers[0]도 바뀜

📌 같은 책을 두 개의 변수명이 함께 보고 있는 것


🔍 차이를 그림으로 이해하기

✅ 사본일 때

numbers        → [ 0, 1, 2, 3, ..., 10 ]
reversed_list  → [10, 9, 8, ..., 0 ]   (별도의 리스트)
 

❌ 참조일 때

numbers   ↘
           → [ 11, 1, 2, 3, ..., 10 ]
numbers2 ↗  (같은 리스트를 가리킴)

✅ 핵심 정리


 

비교 항목  사본(copy) 참조(reference)
생성 방식 [:], [::-1], copy() 단순 대입 a = b
연결 관계 완전히 다른 리스트 같은 리스트 가리킴
원본 영향 없음 서로 영향 줌
예시 reversed_list = numbers[::-1] numbers2 = numbers
 

🧠 Tip

  • 사본을 만들고 싶으면 반드시 슬라이싱, .copy(), list() 등을 사용하세요.
  • 참조가 필요할 땐 그냥 대입하면 됩니다.

반응형