Dev

[Python] * 연산의 오해와 진실, 얕은/깊은 복사

kimyoungrok 2025. 1. 5. 00:48

 Python에서는 * 연산자를 사용하여 리스트나 문자열을 쉽게 복사하거나 확장할 수 있습니다.

 

 이 연산은 매우 간편하지만, 작동 원리를 제대로 이해하지 못하면 의도치 않은 결과를 초래할 수 있습니다.

특히, 리스트와 같은 가변 객체(mutable object) 를 다룰 때는 주의가 필요합니다.

 

 이번 글에서는 Python의 * 연산이 어떻게 작동하는지, 그리고 이를 사용할 때 발생할 수 있는 문제와 해결 방법을 알아보겠습니다.

 


1. * 연산의 기본 원리

Python의 * 연산자는 반복(repetition) 을 통해 객체를 복사하거나 확장하는 역할을 합니다.
대표적으로 문자열, 숫자, 리스트에서 활용됩니다.

 

(1) 문자열과 숫자의 경우

문자열과 숫자는 불변 객체(immutable object) 이므로, * 연산으로 복사해도 안전합니다.

s = "Python"
print(s * 3)  # Output: PythonPythonPython

n = 42
print([n] * 3)  # Output: [42, 42, 42]

 

(2) 리스트의 경우

리스트는 가변 객체(mutable object) 이므로, * 연산 시 주의가 필요합니다. 단순히 참조를 복사하기 때문에, 하나의 요소를 변경하면 모든 복사본이 영향을 받을 수 있습니다.

arr = [0] * 3
print(arr)  # Output: [0, 0, 0]

arr[0] = 1
print(arr)  # Output: [1, 0, 0] (안전)

위 예제는 안전해 보이지만, 2차원 이상의 리스트에서는 문제가 발생할 수 있습니다.


2. 가변 객체에서의 문제: 참조 공유

문제 상황: 2차원 리스트

arr = [[0] * 3] * 3
print(arr)  # Output: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

arr[0][0] = 1
print(arr)  # Output: [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

문제의 원인

[[0] * 3] * 3에서 내부 리스트 [[0] * 3]는 단일 리스트 객체를 참조하며, * 연산은 이 객체를 복사하는 대신 같은 객체를 여러 번 참조합니다.

따라서, 한 곳을 수정하면 모든 참조된 리스트가 동일하게 변경됩니다


3. 해결 방법: 독립적인 객체 생성

리스트 컴프리헨션을 사용

리스트 컴프리헨션을 사용하면 내부 리스트가 독립적인 객체로 생성됩니다.

arr = [[0] * 3 for _ in range(3)]
arr[0][0] = 1
print(arr)  # Output: [[1, 0, 0], [0, 0, 0], [0, 0, 0]]

4. 일반적인 사례와 해결 방법

상황 잘못된 코드 해결 코드
2차원 리스트 초기화 arr = [[0] * N] * N arr = [[0] * N for _ in range(N)]
3차원 리스트 초기화 arr = [[[0] * N] * N] * N arr = [[[0] * N for _ in range(N)] for _ in range(N)]

5. 정리: * 연산의 진실

  • * 연산은 반복확장에 강력한 도구지만, 참조 복사로 인해 의도치 않은 부작용이 발생할 수 있습니다.
  • 리스트와 같은 가변 객체를 다룰 때는 항상 참조의 공유 문제를 염두에 두어야 합니다.
  • 안전한 다차원 리스트 초기화를 위해 리스트 컴프리헨션을 적극 활용하세요.