일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- raycasting
- 엣지컴퓨팅
- schema first
- 어셈블리
- 42seoul
- 동료학습
- 프라이빗클라우드
- 레이캐스팅
- 스플릿키보드
- 텍스트북
- 스타트업
- mistel키보드
- GraphQL
- c++
- uuid-ossp
- 도커
- psql extension
- 파이썬
- 어셈블리어
- 42서울
- SFINAE
- 쿠버네티스
- 부동소수점
- enable_if
- 창업
- Cloud Spanner
- 이노베이션아카데미
- 자료구조
- 정렬
- adminbro
- Today
- Total
written by yechoi
파이썬 2차원 배열 선언, 이 방법은 피하세요! 본문
2차원 배열을 선언해야 하는 백준 BFS 문제를 풀고 있었다. 한 블로그에서 2차원 배열을 선언하는 여러 방법을 올려놨길래, 그 중 내 마음에 제일 드는 짧은 코드를 골라 썼다. 그런데 아무리 봐도 bfs 로직은 틀린 게 없는데, 원하는 답이 안나오는 것...! 한 줄씩 고쳐가면서 확인하다가 찾아냈다. 이유는 2차원 배열 선언 방법이 잘못 됐던 것.
다 읽기 귀찮으신 분들을 위해, 2차원 배열 초기화에 가장 적합한 코드를 미리 써둡니다.
# COLUM : 가로 길이 # ROW : 세로 길이 board = [[0 for i in range(COLUM)] for j in range(ROW)]
대입연산에서 말썽부리는 * 연산자 활용 초기화
내가 택했던 방식은 * 연산자를 활용하는 방법이었다.
board = [[0] * 4] * 4
for i in range(4):
print(board[i])
초기화 결과는 예쁘게 나온다.
[0, 0, 0, 0] [0, 0, 0, 0] [0, 0, 0, 0] [0, 0, 0, 0]
문제는 대입 연산을 진행할 때 발생한다. 여기서 [0,0](1행 1열)을 1로 바꿔보자.
board[0][0] = 1 for i in range(4): print(board[i])
그 결과는...?
[1, 0, 0, 0] [1, 0, 0, 0] [1, 0, 0, 0] [1, 0, 0, 0]
롸...? 얼탱이가 없음 ㅋㅋㅋㅋ 왜 모든 1열이 1로 바뀐 건데....?
문제는 얕은 복사야
문제는 파이썬이 * 연산자로 초기화를 할 때 값을 각각 할당하는 게 아니고, 하나의 객체를 생성해 놓곤 모두가 이를 가리키는 '얕은 복사'를 진행한다는 데서 발생한다.
[0] * 4는 이런 방식으로 동작합니다
[0] * 4는 이렇게 동작한다. 하나의 0 정수형 객체를 생성하고, 배열의 각 요소들이 이를 가리킨다. 0이 4개가 아닌 1개만 생성되는 것.
[[0] * 4] * 4 는 이런 방식으로 동작합니다
먼저 첫번째 배열이 생성되고 나면, 두번째 - 세번째 - 네번째 배열이 모두 처음 생성된 배열을 가리킨다. 1차원 배열은 네 개가 아닌 하나 생긴거고, 모두가 이를 가리키고 있다고 생각하면 되겠다.
배열의 값을 바꿔 봅시다
이제 그럼 배열의 값을 바꿔보자. 일단 board[0][0] = 1 을 하면 board[0][0]은 0을 가리키고 있다가, 새로 정수 객체 1을 생성하고 이를 가리킨다. 여기까진 의도한 대로 바뀌었다.
문제는 다른 배열들이 첫번째 배열을 가리키고 있다는 것이다. board[1][0], board[2][0], board[3][0]도 모두 결국 board[0][0]을 가리키고 있으므로, 이 값들 모두 새로 생성된 정수 객체 1을 가리킨다.
복사는 for 문을 활용합시다
얕은 복사를 피하려면 for문을 활용하는 게 좋다. 도입부에 써놓은 열 복사, 행 복사 모두 for 문으로 해준다면 얕은 복사를 완전히 피할 수 있겠다. 그렇지 않더라도 열 복사가 아닌 행 복사만 *연산자가 아닌 for문을 활용하더라도 이런 문제는 피할 수 있다.
board = [[0] * 4 for _ in range(4)] board[1][2] = 1 for i in range(4): print(board[i])
이 코드는 초기화와 대입 연산 모두 아름답게 의도한 대로 나온다.
# 초기화 결과 [0, 0, 0, 0] [0, 0, 0, 0] [0, 0, 0, 0] [0, 0, 0, 0] # board[1][2] = 1 결과 [0, 0, 0, 0] [0, 0, 1, 0] [0, 0, 0, 0] [0, 0, 0, 0]
* 출처 :