P2-8.7 보충학습: 참조와 복사 구분¶
Section ID:
P2-8.7Version:v2026.09.15
대입과 참조¶
대입(assignment)은 이름과 객체를 연결합니다. other_scores = scores는 새 리스트를 만들지 않고, scores가 가리키는 리스트를 other_scores도 가리키게 합니다. 이름이 객체를 가리키는 관계를 참조(reference)라고 합니다.
점수 [82, 75, 91]을 두 이름으로 참조한 뒤 other_scores에 68을 추가합니다. 두 출력 모두 [82, 75, 91, 68]입니다.
출력 예시는 다음과 같습니다.
여기서는 scores와 other_scores가 같은 리스트를 가리킵니다. 그래서 한쪽 이름으로 값을 추가하면 다른 이름으로 봐도 같은 변화가 보입니다.
같은 값과 같은 객체¶
==는 값이 같은지를, is는 같은 객체인지를 비교합니다. 리스트 내용을 같게 복사해도 두 리스트가 같은 객체가 되는 것은 아닙니다.
출력은 True, False, True입니다. 값 비교만으로 원본과 복사본이 분리됐다고 판단할 수 없습니다. 아래 화살표는 이름이 가리키는 객체를 나타냅니다.
flowchart LR
A["scores"] --> L["리스트 A: 82, 75"]
B["alias"] --> L
C["copied"] --> M["리스트 B: 82, 75"] 숫자나 문자열의 값 비교에는 ==를 사용합니다. 내부 객체 재사용 여부에 기대어 is로 값을 비교하지 않습니다. 값이 없음을 확인할 때 쓰는 value is None은 None 객체인지를 묻는 비교입니다.
얕은 복사¶
얕은 복사(shallow copy)는 바깥쪽 컨테이너만 새로 만들고, 안쪽에 들어 있는 값은 그대로 참조할 수 있는 복사입니다.
scores.copy()로 새 바깥 리스트를 만든 뒤 복사본에 68을 추가합니다. 원본은 [82, 75, 91], 복사본은 [82, 75, 91, 68]입니다.
출력 예시는 다음과 같습니다.
이 경우에는 바깥 리스트 자체가 새로 만들어졌기 때문에 append() 결과가 원본에 바로 반영되지는 않습니다.
바깥 리스트에 항목을 추가하는 것과 안쪽 리스트의 항목을 바꾸는 것은 서로 다른 객체를 수정하는 일입니다.
중첩 리스트의 공유¶
중첩 리스트 [[1, 2], [3, 4]]를 얕게 복사한 뒤 첫 행의 첫 값을 99로 바꿉니다. 원본과 복사본 모두 [[99, 2], [3, 4]]가 됩니다.
출력 예시는 다음과 같습니다.
matrix와 shallow는 서로 다른 바깥 리스트이지만, 두 리스트의 첫 항목은 같은 행 리스트를 가리킵니다. shallow[0][0] = 99는 그 공유된 행 안의 값을 바꿉니다.
수정 줄을 shallow[0] = [99, 2]로 바꿔 처음부터 실행하면 원본은 [[1, 2], [3, 4]]로 유지됩니다. 이 대입은 공유된 행을 수정하는 대신 복사본의 첫 항목을 새 행으로 교체하기 때문입니다.
깊은 복사¶
깊은 복사(deep copy)는 복사 가능한 내부 객체를 재귀적으로 복사합니다. 이 예시에서는 바깥 리스트와 안쪽 행 리스트를 모두 새로 만듭니다.
같은 중첩 리스트를 copy.deepcopy()로 복사하면 안쪽 행 리스트도 새로 만들어집니다. 복사본의 첫 값을 99로 바꿔도 원본은 [[1, 2], [3, 4]]로 남습니다.
출력 예시는 다음과 같습니다.
바깥 리스트와 안쪽 리스트 중 어디를 바꾸는지에 따라 원본에 미치는 영향이 달라집니다. 깊은 복사가 모든 객체를 새로 만든다는 뜻은 아닙니다. 불변 객체는 재사용될 수 있고 파일·소켓 같은 외부 자원을 복제하는 방법도 아닙니다.
| 방식 | 직관 | 중첩 구조에서 주의할 점 |
|---|---|---|
| 대입 | 같은 대상을 다른 이름으로 본다 | 한쪽 변경이 그대로 함께 보일 수 있음 |
| 얕은 복사 | 바깥쪽만 새로 만든다 | 안쪽 중첩 값은 공유될 수 있음 |
| 깊은 복사 | 안쪽까지 새로 만든다 | 원본 보존에는 유리하지만 비용이 더 들 수 있음 |
사례: 실험용 점수 목록의 원본 보존¶
중첩 리스트 [[10, 20], [30, 40]]에서 첫 행의 첫 값을 -1로 바꿉니다. A는 대입, B는 얕은 복사, C는 깊은 복사이며 각 실험은 새 원본으로 시작합니다. A와 B에서는 원본도 바뀌고, C에서는 원본이 유지됩니다.
출력 예시는 다음과 같습니다.
B에서 첫 행의 항목 수정은 원본에도 영향을 줍니다. 반면 수정 줄을 case_b.append([50, 60])으로 바꿔 처음부터 실행하면 원본은 두 행으로 남고 복사본만 세 행이 됩니다. 원본 보존에 필요한 복사 범위는 실제로 수정할 객체가 어디에 있는지에 따라 결정됩니다.
체크리스트¶
- 같은 리스트를 두 이름이 함께 가리킬 수 있다는 점을 설명할 수 있는가?
- 얕은 복사와 깊은 복사의 차이를 중첩 리스트 예제로 설명할 수 있는가?
- 왜 데이터 전처리에서 복사 여부를 조심해야 하는지 말할 수 있는가?
-
대입, 얕은 복사, 깊은 복사를 원본 공유 여부로 구분할 수 있는가?
-
==와is가 각각 값과 객체 정체성을 비교한다는 점을 설명할 수 있는가?
출처와 참고 자료¶
- Python Software Foundation, The Python Tutorial - More on Lists, Python 3 documentation, 확인 날짜: 2026-07-20. 리스트 대입,
list.copy(), 슬라이스 복사, 리스트 메서드 예시를 확인하는 근거로 사용했다. -
Python Software Foundation, Standard Library -
copy, Python 3 documentation, 확인 날짜: 2026-09-15. 대입과 복사의 차이, 얕은 복사와 깊은 복사의 정의, 중첩 객체 복사 차이를 확인하는 핵심 근거로 사용했다. -
Python Software Foundation, Built-in Types: Comparisons, 2026-09-15. 값 비교와 객체 정체성 비교의 구분.