P2-8.7 보충학습: 참조와 복사 구분¶
Section ID:
P2-8.7Version:v2026.07.23
P2-8.2에서는 리스트(list)를 다른 이름에 대입했다고 해서 자동으로 새 복사본이 생기지 않는다는 점을 봤습니다. 이 지점에서 많은 독자가 바로 헷갈립니다.
같은 값을 다른 이름으로 부른 것인가?
아니면 비슷한 값을 새로 하나 더 만든 것인가?
여기서는 참조(reference), 얕은 복사(shallow copy), 깊은 복사(deep copy)를 구분하는 기본 보충 설명을 제공합니다. 이 보충학습은 리스트와 딕셔너리 구조가 실제로 같은 대상을 함께 보고 있는지, 분리된 사본인지 판단하는 기준을 정리합니다.
이 보충학습에서는 Python의 메모리 모델을 깊게 설명하기보다, 데이터 처리와 실습 코드에서 원본이 같이 바뀌는가를 읽는 최소 기준을 만듭니다.
| 용어 | 이 절에서 먼저 잡을 뜻 |
|---|---|
| 참조(reference) | 여러 이름이 같은 객체를 함께 가리키는 상태입니다. |
| 대입(assignment) | 새 복사를 보장하지 않고 이름을 다른 값이나 객체에 연결하는 동작입니다. |
| 얕은 복사(shallow copy) | 바깥 컨테이너만 새로 만들고 안쪽 값은 공유할 수 있는 복사입니다. |
| 깊은 복사(deep copy) | 안쪽 중첩 값까지 새로 만들어 원본과 분리하는 복사입니다. |
| 중첩 구조(nested structure) | 리스트 안에 리스트처럼 내부에 또 다른 묶음이 들어 있는 구조입니다. |
처음 읽는 기준: 참조와 복사 구분¶
- 같은 객체(object)를 두 이름이 함께 가리킬 수 있음을 설명할 수 있습니다.
- 얕은 복사(shallow copy)를 바깥쪽 껍질만 새로 만드는 복사로 설명할 수 있습니다.
- 깊은 복사(deep copy)를 안쪽에 중첩된 값까지 새로 복사하는 방식으로 설명할 수 있습니다.
- 중첩 리스트에서 얕은 복사가 왜 원본과 함께 바뀌는 것처럼 보일 수 있는지 설명할 수 있습니다.
- 데이터 전처리에서 원본 보존이 중요할 때 복사 여부를 먼저 점검해야 함을 설명할 수 있습니다.
학습 배경¶
초반 Python 학습에서는 값 하나를 변수에 넣고 바꾸는 장면이 많습니다. 하지만 리스트, 딕셔너리, DataFrame처럼 내부에 여러 값을 담는 구조를 다루기 시작하면 무엇을 바꿨는가만큼 어느 대상을 바꿨는가가 중요해집니다.
이 감각은 뒤의 Pandas와 데이터 전처리에서도 다시 필요합니다. 표를 다룰 때 원본을 보존할지, 중간 결과를 새로 만들지, 같은 객체를 여러 이름으로 참조하고 있는지에 따라 결과 해석이 달라질 수 있기 때문입니다.
주요 학습내용¶
이 보충학습에서는 먼저 다음 세 가지 구분을 큰 틀로 잡습니다.
| 구분 | 먼저 붙잡을 질문 | 지금 단계에서의 핵심 감각 |
|---|---|---|
| 대입 | 같은 값을 새로 만든 것인가, 같은 대상을 다른 이름으로 부르는 것인가? | 대입은 자동 복사를 뜻하지 않는다 |
| 얕은 복사 | 어디까지 새로 만들고 어디까지 함께 보는가? | 바깥쪽만 새로 만들고 안쪽은 공유될 수 있다 |
| 깊은 복사 | 원본과 완전히 분리된 복사본이 필요한가? | 중첩된 안쪽 값까지 새로 만든다 |
이 세 구분을 먼저 잡아 두면, 뒤의 리스트 처리와 데이터 전처리 예제에서 왜 원본이 같이 바뀌었는가를 더 빠르게 읽을 수 있습니다.
세부 학습내용¶
같은 리스트를 두 이름이 함께 가리킬 수 있다¶
가장 먼저 붙잡아야 할 점은 대입(assignment)이 항상 복사(copy)를 뜻하지는 않는다는 것입니다.
문제 상황: 리스트를 다른 변수에 대입했을 때 두 이름이 같은 대상을 함께 보는지 확인하고 싶습니다. 입력(input): 리스트 scores와 같은 리스트를 가리키는 other_scores. 기대 출력(output): 한쪽에 값을 추가하면 두 이름으로 본 결과가 함께 바뀝니다. 확인할 개념: 단순 대입은 새 복사본 생성을 보장하지 않습니다.
출력 예시는 다음과 같습니다.
여기서는 scores와 other_scores가 같은 리스트를 가리킵니다. 그래서 한쪽 이름으로 값을 추가하면 다른 이름으로 봐도 같은 변화가 보입니다.
여기서는 이렇게 기억합니다.
a = b는 새 복사본을 만든다고 자동으로 보장하지 않습니다.- 변경 가능한 값(mutable object)은 같은 객체를 여러 이름이 함께 볼 수 있습니다.
얕은 복사는 바깥쪽만 새로 만든다¶
얕은 복사(shallow copy)는 바깥쪽 컨테이너만 새로 만들고, 안쪽에 들어 있는 값은 그대로 참조할 수 있는 복사입니다.
문제 상황: 바깥 리스트만 새로 만든 얕은 복사가 원본과 어떻게 달라지는지 보고 싶습니다. 입력(input): 리스트 scores와 scores.copy()로 만든 copied_scores. 기대 출력(output): copied_scores에만 값이 추가되고 원본 scores는 그대로 남습니다. 확인할 개념: 얕은 복사는 바깥쪽 컨테이너를 새로 만들기 때문에 최상위 추가/삭제는 분리될 수 있습니다.
출력 예시는 다음과 같습니다.
이 경우에는 바깥 리스트 자체가 새로 만들어졌기 때문에 append() 결과가 원본에 바로 반영되지는 않습니다.
하지만 여기서 끝나면 얕은 복사를 다 이해한 것이 아닙니다. 안쪽에 또 리스트가 들어 있으면 이야기가 달라집니다.
중첩 리스트에서는 얕은 복사가 헷갈리기 쉽다¶
다음처럼 리스트 안에 리스트가 들어 있는 경우를 봅니다.
문제 상황: 중첩 리스트에서는 얕은 복사가 왜 헷갈리는지 직접 확인하고 싶습니다. 입력(input): 중첩 리스트 matrix와 그 얕은 복사본 shallow. 기대 출력(output): 안쪽 리스트를 바꾸면 원본과 얕은 복사본이 함께 달라집니다. 확인할 개념: 얕은 복사는 안쪽 중첩 객체까지 새로 만들지 않을 수 있습니다.
출력 예시는 다음과 같습니다.
왜 이런 일이 생길까요?
- 바깥 리스트
matrix는 새로 복사되었습니다. - 하지만 안쪽의
[1, 2],[3, 4]리스트는 그대로 공유될 수 있습니다.
즉, 얕은 복사는 겉 상자만 새로 만들고, 상자 안의 작은 상자들은 그대로 둘 수 있다는 비유로 이해하면 좋습니다.
깊은 복사는 안쪽까지 새로 만든다¶
깊은 복사(deep copy)는 중첩된 내부 값까지 새로 복사합니다.
문제 상황: 깊은 복사가 안쪽 중첩 값까지 분리하는지 확인하고 싶습니다. 입력(input): copy.deepcopy(matrix)로 만든 deep. 기대 출력(output): deep을 바꿔도 원본 matrix는 그대로 남습니다. 확인할 개념: 깊은 복사는 중첩된 내부 구조까지 새로 만들어 원본과 분리합니다.
출력 예시는 다음과 같습니다.
이제는 안쪽 리스트까지 새로 생겼기 때문에 deep을 바꿔도 matrix는 그대로 남습니다.
여기서는 다음 기준으로 구분합니다.
| 방식 | 직관 | 중첩 구조에서 주의할 점 |
|---|---|---|
| 대입 | 같은 대상을 다른 이름으로 본다 | 한쪽 변경이 그대로 함께 보일 수 있음 |
| 얕은 복사 | 바깥쪽만 새로 만든다 | 안쪽 중첩 값은 공유될 수 있음 |
| 깊은 복사 | 안쪽까지 새로 만든다 | 원본 보존에는 유리하지만 비용이 더 들 수 있음 |
사례 및 예시¶
데이터 전처리에서는 원본 표를 남겨 두고 실험용 사본을 따로 만들고 싶을 때가 많습니다.
- 원본 데이터는 보관한다.
- 파생 열을 추가한 실험본은 따로 만든다.
- 필터링 결과를 비교하려면 중간 버전도 남긴다.
이때 복사 여부를 의식하지 않으면, 원본을 보존한다고 생각했는데 실제로는 같은 객체를 같이 바꾸는 문제가 생길 수 있습니다.
Pandas에서는 이런 문제를 더 조심해야 합니다. 다만 Pandas의 copy()와 view/view-like 동작 세부는 이 절에서 깊게 다루지 않고, Part 2 Chapter 12에서 데이터셋을 준비할 때 원본 보존이 필요한가를 먼저 묻는 태도로 연결합니다.
사례 1. 전처리용 목록을 따로 만들었는데 원본도 같이 바뀌는 이유¶
한 학습자가 원본 점수 목록을 보존한 채 실험용 목록만 수정하려고 했다고 하겠습니다. 그래서 experiment_scores = base_scores라고 적고 한쪽 목록만 고쳤는데, 나중에 보니 원본도 함께 바뀌어 있습니다.
사람이 먼저 쓰는 기준은 이름을 새로 만들었으니 복사됐겠지입니다. 하지만 변경 가능한 구조에서는 대입이 곧 새 복사본을 뜻하지 않을 수 있습니다. 특히 리스트 안에 또 리스트가 들어 있는 중첩 구조에서는 겉만 복사했는지, 안쪽까지 새로 만든 것인지가 결과를 크게 바꿉니다.
이 보충학습이 참조, 얕은 복사, 깊은 복사를 나누는 이유도 여기에 있습니다. 데이터 전처리에서는 원본 보존이 자주 중요하기 때문에, 지금 바꾸는 대상이 원본과 분리되어 있는가를 먼저 점검해야 합니다.
확인 가능한 결과는 한쪽을 바꿨을 때 다른 이름으로 본 값도 함께 달라지는지입니다. 한쪽 수정이 다른 쪽에도 즉시 보이면 같은 객체를 함께 보고 있을 가능성이 크고, 중첩 구조에서 바깥만 복사했다면 얕은 복사를 의심해야 합니다.
연습 및 예제¶
다음 코드를 보고 각 경우가 대입, 얕은 복사, 깊은 복사 중 무엇인지 먼저 맞혀 봅니다.
문제 상황: 대입, 얕은 복사, 깊은 복사를 한 번에 비교해 차이를 눈으로 확인하고 싶습니다. 입력(input): 중첩 리스트 base와 case_a, case_b, case_c. 기대 출력(output): A와 B에서는 원본이 함께 바뀌고, C에서는 원본이 유지됩니다. 확인할 개념: 중첩 구조에서는 대입과 얕은 복사가 원본 공유를 만들 수 있고, 깊은 복사는 이를 끊습니다.
출력 예시는 다음과 같습니다.
여기서 핵심은 B입니다. 바깥쪽은 복사했지만 안쪽 리스트가 함께 바뀌므로, 얕은 복사가 어디까지 새 대상을 만드는지 눈으로 확인할 수 있습니다.
체크리스트¶
- 같은 리스트를 두 이름이 함께 가리킬 수 있다는 점을 설명할 수 있는가?
- 얕은 복사와 깊은 복사의 차이를 중첩 리스트 예제로 설명할 수 있는가?
- 왜 데이터 전처리에서 복사 여부를 조심해야 하는지 말할 수 있는가?
- 대입, 얕은 복사, 깊은 복사를 원본 공유 여부로 구분할 수 있는가?
출처와 참고 자료¶
- Python Software Foundation, The Python Tutorial - More on Lists, Python 3.14.6 documentation, 확인 날짜: 2026-07-20. 리스트 대입,
list.copy(), 슬라이스 복사, 리스트 메서드 예시를 확인하는 근거로 사용했다. - Python Software Foundation, Standard Library -
copy, Python 3.14.6 documentation, 확인 날짜: 2026-07-20. 대입과 복사의 차이, 얕은 복사와 깊은 복사의 정의, 중첩 객체 복사 차이를 확인하는 핵심 근거로 사용했다.