오늘은 파이썬의 변수 할당에 대해서 알아보겠다. 매일 코테문제를 풀고있었는데도 이런 기초적인 것도 몰랐다는 것에 쑥스러웠다. 갑자기 이걸 작성하게 된 이유는 평소처럼 백준 문제를 풀고있었는데, 이상한 곳에서 계속 오류가 나는 것 때문이었다. 내 코드가 잘못된 것도 아니고 어려운 함수를 쓴 것도 알고리즘을 쓴것도 아니고 맨날 하던 변수선언후 append를 하고있었는데 값이 계속 변하는 것이었다. 도저히 해결을 못해서 백준에 질문을 남겼고 recoma 님이 답변을 주셨다ㅠㅠ 정말 감사합니다. 우선 해당 질문글은 이것이다.
위 질문글을 읽어보면 알겠지만, pos라는 배열에는 좌표를 저장하고 있었는데 분명 pos는 계속 변했고 한번 바뀔 때마다 rom이라는 리스트에 append하고 있었다. 그런데 새로 넣을 때마다 rom안의 인자는 건들지도 않았는데 계속 인자가 제일 최신 좌표로 새로고침됐다. 즉 rom에 (1,2)를 넣고 (2,3)이라는 좌표를 새로 추가하면 rom에 (2,3),(2,3)이렇게 제일 최신좌표들만 들어가있었다. 반복문을 돌렸고 append하는 코드도 정확한 위치에 넣어줬는데 저렇게 나오니까 답답해서 미쳐버릴뻔했다. 처음에는 반복문 문제인가하고 파이썬의 반복문에 대해서도 검색해봤지만 답변을 못얻었다. 이후 recoma님이 설명해주신 글을 보고 한번에 이해했다.
C언어를 배우신 분이라면 더 확 와닿을 것이다. C언어를 배울때마다 계속 머리를 복잡하게 하던 포인터 개념이 이번 파이썬에서도 동일한 것이었다. 파이썬에서는 포인터라는 개념자체는 없지만 지금 설명하려는 것은 그것과 매우 유사하다. 우선 파이썬에서 변수를 선언하면 id값이 부여되는데 이 id값이 C언어에서 자주 나오던 주소값과 유사한 개념이다.
import sys
input=sys.stdin.readline
t=int(input())
for i in range(t):
rom=[]
pos=[0,0]
nav=[1,0,0,0]
command=input()
for j in command:
if(nav[0]==1):
if(j=='f'):
pos[1]+=1
elif(j=='b'):
pos[1]-=1
elif(j=='l'):
nav[0],nav[2]=0,1
elif(j=='r'):
nav[0],nav[3]=0,1
elif(nav[1]==1):
if(j=='f'):
pos[1]-=1
elif(j=='b'):
pos[1]+=1
elif(j=='l'):
nav[1],nav[3]=0,1
elif(j=='r'):
nav[1],nav[2]=0,1
elif(nav[2]==1):
if(j=='f'):
pos[0]-=1
elif(j=='b'):
pos[0]+=1
elif(j=='l'):
nav[2],nav[1]=0,1
elif(j=='r'):
nav[2],nav[0]=0,1
else:
if(j=='f'):
pos[0]+=1
elif(j=='b'):
pos[0]-=1
elif(j=='l'):
nav[3],nav[0]=0,1
elif(j=='r'):
nav[3],nav[1]=0,1
rom.append(pos)
print(rom)
print(rom)
rom=[]
코드를 보면 나는 pos배열의 인자를 계속 값만 변경중이다. 따라서 pos 자체의 id는 변하지 않았고 계속 동일했던 것이다. 이래서 반복문을 돌면서 pos를 추가하면 계속 똑같은 주소값을 넣기때문에 마지막값만 넣어진 것처럼 보이게 된 것이다. 따라서 이걸 해결하려면 매 반복문마다 새로운 변수를 넣어줘야했고 이는 초기화를 해주면 됐다. pos를 초기화하면서 pos안의 인자들은 유지해야하므로 pos=pos.copy()를 통해서 pos의 id값을 새로 받아오면서 안의 인자는 유지할 수 있다. recoma님이 잘 설명해주신 예제를 보면 아래 코드처럼 b=a라고 변수를 선언하면 b는a와 같은 id를 사용하는 것을 볼 수 있다. 따라서 a의 값만 변경해줬더라도 b도 같이 변경된다 왜냐면 같은 객체를 가리키고 있기 때문이다. 즉 이것을 해결하기 위해 copy함수를 써서 안의 데이터는 똑같지만 다른id를 가진 객체를 만들어서 해결하는 것이다.
a = [0,1]
b = a
print(id(a), id(b))
>>>2264869492928 2264869492928 #같은 id = 같은 객체
a[0] += 1
a
>>>[1, 1]
b
>>>[1, 1] # 그렇기에 a의 요소만 바뀌도 b까지 바뀐다
# copy함수를 사용한 복사
b = a.copy()
print(id(a), id(b))
>>>2264869492928 2264869216704 # 다른 id = 다른 객체
a[0] += 1
a
>>>[2, 1]
b
>>>[1, 1] # 다른 객체이므로 a만 바뀐다.
더욱 자세한 설명은 다른 분의 블로그도 링크 달아두겠습니다.!
'코딩테스트 > 파이썬 알고리즘' 카테고리의 다른 글
Algorithms-[deque] (0) | 2022.01.19 |
---|---|
Algorithms-[Two Pointer] (0) | 2022.01.11 |
Algorithms-[BFS] (0) | 2021.12.30 |
Algorithms-[Dynamic_Programming] (0) | 2021.12.19 |
Algorithms-[Que & Stack] (0) | 2021.12.07 |