기초 노트/Python

파이썬 - 이중 리스트 초기화시 주의점

플로라도 2023. 11. 6. 00:31

이중 리스트 같은 경우

간단히 리스트 컴프리헨션을 사용함으로써 초기화를 할 수 있다.

 

array[1][1] = 3으로 할당하면

아래와 같이 두번째 row의 두번째 요솟값만 3으로 바뀐걸 알 수 있다.

 

m = 3
n = 4

array = [[0]*m for _ in range(n)]
array[1][1]=3
array
>>> [[0, 0, 0], [0, 3, 0], [0, 0, 0], [0, 0, 0]]

 

 

그러나 만약 아래의 코드로 이중리스트를 초기화 한다고 하면 문제가 생긴다.

array = [[0]*m]*n 으로 초기화 후 , array[1][1]=5를 할당하면 

array= [[0]*m]*n
array[1][1]=5
array
>>> [[0, 5, 0], [0, 5, 0], [0, 5, 0], [0, 5, 0]]

모든 sublist, 모든row의 두번째 요솟값들이 전부 5로 바뀌는것을 알 수 있다.

 

 

실제 주피터 노트북상에서의 결과도 아래와 같이 확인할 수 있다.

 

 

 

이러한 현상의 이유는 자료형의 타입때문인데,

기본적으로 파이썬에서 정수형(int)은 불변형(immutable)의 자료형이고

리스트는 변경가능한(mutable) 자료형이다.

이러한 사실을 상기하고 다음의 코드를 차례대로 다시 살펴보자.

 

 

(1) [0]*n

(2) [[0]*m]*n

(3) [[0]*m for _ in range(n)]

먼저 [0] * m 의 코드는 m 개의 0이 포함된 리스트를 만든다.

여기서 중요한 점은 각각의 0이 독립적인 정수 객체라는 것이다.

파이썬에서 정수는 앞서 이야기 했듯, 불변(immutable)객체이므로, 각 0은 메모리 상에서 서로 다른 객체를 참조하게 된다. 따라서 같은 값을 가지더라도 실제로는 독립된, 서로 다른 메모리 주소값을 가지는 여러개의 객체다.

 

 

[[0]*m]*n 의 코드는 정수형 0이 m번 반복된 리스트를 n번 반복한다.

다시 말해서,

[[0]*m]*n 의 코드는 immutable객체인 정수형 0이 m번 반복된 mutable 리스트를 n번 반복한다.

여기서 반복은 mutable객체인 리스트를 반복하기 때문에 얕은 복사가 이루어져 동일한 리스트(같은 메모리값)를 참조하는 n번의 반복이 된다.

 

 

마지막 리스트 컴프리헨션이 사용된 코드는

[0]*m이 생성되고 리스트 컴프리헨션 ( 가장 바깥 대괄호 '[' , ']' ) 에 의해 [0]*m 마다 별도의 리스트로,서로 다른 독립적인 메모리 할당이 이루어진다. 따라서 이 경우에는 어떤 행의 원소를 변경해도, 다른행에 영향이 가지 않게 된다.