파이썬에서 2차원 리스트를 만들 때는 종종 다음과 같이 두 가지 방식이 사용됩니다.
# 방법 1: 리스트 내포 (list comprehension)
marks1 = [['~'] * 3 for _ in range(4)]
# 방법 2: 곱하기 연산자 (*)
marks2 = [['~'] * 3] * 4
겉보기에는 똑같이 4x3 형태의 2차원 리스트처럼 보이지만, 내부 동작은 전혀 다릅니다.
1. 리스트 내포 방식 (marks1)
marks1 = [['~'] * 3 for _ in range(4)]
- 리스트 내포를 사용할 경우, for 반복마다 새로운 리스트 객체가 생성됩니다.
- 따라서 marks1의 각 행은 서로 독립된 객체입니다.
marks1[0][1] = 'X'
print(marks1)
# [['~', 'X', '~'], ['~', '~', '~'], ['~', '~', '~'], ['~', '~', '~']]
첫 번째 행만 변경되고, 나머지 행에는 영향이 없습니다.
2. 곱하기 연산자 방식 (marks2)
marks2 = [['~'] * 3] * 4
- ['~'] * 3 리스트 하나를 만든 뒤, 그 동일한 객체를 4번 참조하는 구조입니다.
- 따라서 4개의 행은 사실 모두 같은 리스트를 공유합니다.
marks2[0][1] = 'X'
print(marks2)
# [['~', 'X', '~'], ['~', 'X', '~'], ['~', 'X', '~'], ['~', 'X', '~']]
한 행을 수정했는데, 모든 행이 동시에 바뀌어버렸습니다.
3.참조 구조 확인하기
print([id(i) for i in marks1])
print([id(i) for i in marks2])
이 현상의 이름은?
많은 분들이 이를 깊은 복사 vs 얕은 복사 문제라고 표현하지만, 사실 더 정확한 표현은 참조 공유(reference sharing) 문제입니다.
- marks1 → “깊은 복사처럼” 각 행이 독립적
- marks2 → “얕은 복사보다 더 심각한” 동일 객체 참조
즉, 리스트 내포는 안전하게 독립 객체를 만들고, * 연산자는 같은 객체를 반복 참조한다고 이해하는 것이 핵심입니다.
정리하면
파이썬에서 2차원 리스트를 만들 때는 [['~'] * 3 for _ in range(4)]처럼 리스트 내포를 쓰는 것이 안전합니다.
곱하기(*) 연산자를 쓰면 의도치 않게 모든 행이 연결되어 버릴 수 있으니 주의해야 합니다.
'파이썬 > 기초 프로그래밍' 카테고리의 다른 글
| 파이썬 sorted() vs 리스트 .sort() 제대로 정리하기 (0) | 2025.09.07 |
|---|---|
| 파이썬의 시퀀스형(Sequence) (0) | 2025.09.07 |
| Python list, filter, map 쉽게 이해하기 (0) | 2025.09.07 |
| 파이썬 NamedTuple 간단 정리 (0) | 2025.09.06 |
| 파이썬 데이터 모델링: 매직 메서드로 객체를 데이터처럼 다루기 (0) | 2025.09.06 |