Language/Python&Django

파이썬에서 2차원 리스트를 생성할 때 주의해야할 점.

지과쌤 2021. 2. 10.
반응형

해당 포스트는 https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/ 를 토대로 작성하였습니다.


파이썬에서 2차원 리스트를 생성할때 대부분 두가지 방법을 사용하게 된다. 두가지 방법을 차례대로 비교해보며 마주칠 수 있는 이슈에 대해 알아보자.


0으로 이뤄진 길이N의 1차원 리스트를 생성해보자.

 

Method 1a

# First method to create a 1 D array 
N = 5
arr = [0]*N 
print(arr) 

Output:

[0, 0, 0, 0, 0]

 

Method 1b

# Second method to create a 1 D array 
N = 5
arr = [0 for i in range(N)] 
print(arr) 

Output:

[0, 0, 0, 0, 0]

아래 방법을 통해 2차원 리스트를 생성할 수 있다.

 

Method 2a

# Using above first method to create a 
# 2D array 
rows, cols = (5, 5) 
arr = [[0]*cols]*rows 
print(arr) 

Output:

[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

 

Method 2b

# Using above second method to create a 
# 2D array 
rows, cols = (5, 5) 
arr = [[0 for i in range(cols)] for j in range(rows)] 
print(arr) 

Output:

[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Method 2c

# Using above second method to create a 
# 2D array 
rows, cols = (5, 5) 
arr=[] 
for i in range(cols): 
	col = [] 
	for j in range(rows): 
		col.append(0) 
	arr.append(col) 
print(arr) 

Output:

[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

 

위의 방법들은 모두 같은 리스트를 만드는것처럼 보인다. 그럼 이제 Method 2aMethod 2b의 원소를 하나 바꿔보도록 하자.

# Python 3 program to demonstrate working 
# of method 1 and method 2. 

rows, cols = (5, 5) 

# method 2a 
arr = [[0]*cols]*rows 

# lets change the first element of the 
# first row to 1 and print the array 
arr[0][0] = 1

for row in arr: 
	print(row) 
# outputs the following 
#[1, 0, 0, 0, 0] 
#[1, 0, 0, 0, 0] 
#[1, 0, 0, 0, 0] 
#[1, 0, 0, 0, 0] 
#[1, 0, 0, 0, 0] 

print("--------------")

# method 2b 
arr = [[0 for i in range(cols)] for j in range(rows)] 

# again in this new array lets change 
# the first element of the first row 
# to 1 and print the array 
arr[0][0] = 1
for row in arr: 
	print(row) 

# outputs the following as expected 
#[1, 0, 0, 0, 0] 
#[0, 0, 0, 0, 0] 
#[0, 0, 0, 0, 0] 
#[0, 0, 0, 0, 0] 
#[0, 0, 0, 0, 0] 

Output:

[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
[1, 0, 0, 0, 0]
--------------
[1, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]

첫번째 행의 첫번째 원소만 바뀌어야하는데, Method 2a의 경우, 각 행의 첫번째 원소가 모두 바뀌어버렸다.

이는, 얕은 복사(shallow copy) 때문이다.


Method 1a( "arr = [0]*N" )에서, 파이썬은 5개의 정수형 오브젝트를 생성하는것이 아닌, 단 하나의 정수형 오브젝트만 생성한다.

 

그리고, 아래 사진과 같이 배열 arr의 모든 인덱스는 하나의 정수형 오브젝트를 가르킨다.

 

만약 0번째 인덱스에 숫자 1을 선언하면, value값 1을 가진 새로운 정수형 오브젝트가 만들어지고, 0번째 인덱스는 아래 사진과 같이 새로 만들어진 정수형 오브젝트를 가르키게된다.


이제 2차원 배열이다.

 

 “arr = [[0]*cols]*rows” 로 2차원 배열을 생성한다면 아래와 같은 절차를 따르게 된다.

 

  1. 정수형 오브젝트가 하나 생성된다.
  2. 1차원 리스트 하나가 만들어지고, 리스트의 모든 인덱스는 1번의 정수형 오브젝트를 가르킨다.
  3. 그리고 arr[0], arr[1], arr[2] ... arr[n-1] 내부의 1차원 리스트들은 모두 2번에서 만들어진 리스트 오브젝트를 가르키게 된다.

위 과정을 아래 사진으로 표현할 수 있겠다.

안쪽이 먼저 만들어진 1차원 리스트. 그리고 그 리스트가 각각 arr[0], arr[1] ... 에 들어가고, 결국 동일한 오브젝트를 가르킨다.

 

그럼 이제 " arr[0][0] = 1 " 를 사용하여 리스트 "arr" 의 첫번째 행에서 첫번째 요소를 변경해보도록 하자.

 

=>arr[0]은 위에서 만든 1차원 리스트를 가르킨다. ( arr[1], arr[2], ... arr[n-1]도 모두 같은 리스트를 가르킨다는것을 기억하자 ) 

=> arr[0][0] 는 value값 1을 갖는 새로운 정수형 오브젝트를 가르키게 된다. ( arr[1][0], arr[2][0] ...arr[n-1][0]도 모두 같은 오브젝트를 가르키게 된다 )

 

위의 이론은 아래 사진으로 표현할 수 있다.

 

따라서, 2차원 배열이 이런식( “arr = [[0]*cols]*rows” )으로 만들어지게 된다면 특정 행에서 값을 변경할 때, 기본적으로 하나의 정수형 오브젝트와 배열의 모든 행에서 가르키는 하나의 리스트 오브젝트만 있기 때문에 모든 행에 영향을 미치게 된다.


따라서 2차원 리스트를 생성할때는 아래 방법을 사용하는것이 좋겠다.

rows, cols = (5, 5) 
arr = [[0 for i in range(cols)] for j in range(rows)] 

 

is연산자를 사용해 아래와 같이 같은 주소값을 갖는지 확인할 수 있다.

rows, cols = (5, 5) 
# method 2b 
arr = [[0 for i in range(cols)] for j in range(rows)] 

# check if arr[0] and arr[1] refer to 
# the same object 
print(arr[0] is arr[1]) # prints False 

# method 2a 
arr = [[0]*cols]*rows 

# check if arr[0] and arr[1] refer to 
# the same object 
# prints True because there is only one 
# list object being created. 
print(arr[0] is arr[1]) 

Output:

False
True
반응형

댓글

💲 추천 글