python의 얕은 복사와 깊은 복사

haremeat·2022년 7월 29일
0

Python

목록 보기
4/5
post-thumbnail

파이썬 기본이지만
최근 이것 때문에 버그를 못 찾고 쓸데없이 시간낭비를 한 일이 있었다.
오히려 기본이기때문에 짚고 넘어가고자 한다.

TL;DR

얕은 복사(shallow copy)는 복사를 하더라도 복사된 변수가 같은 주소를 바라보고 있는 것이고, 깊은 복사(deep copy)는 내부의 객체들까지 모두 새롭게 복사된다. 즉 다른 주소값을 가지게 된다.

다만 이는 모두 mutable한 애들(ex. list, set, dict)한테만 적용되는 이야기고, immutable한 객체(ex. tuple)한테는 해당 없는 이야기다.

내가 겪은 문제

내 목적은 특정 프레임(숫자) 리스트에서 없는 숫자만 빼서 각 dict에 넣는 것이었다. 여기서 기본이 되는 프레임 리스트는 어차피 공통 숫자로 구성될 예정이었음.

그래서 난 아래와 같은 코드를 짰다.

for i, answer in enumerate(answer.values()):
	for coord in answer['coordinates']:
		all_frame_list.append(int(coord['frame']))

이렇게 프레임 리스트를 구성하고 not_enough_frames라는 dict를 하나 만들어서 각각 id별로 key를 구성해서 value로 all_frame_list를 넣었다.

not_enough_frames = {
	1: [1,2,3,4,....],
    2: [1,2,3,4,....],
    ...
}

대강 형태는 이런 느낌

int_input_frame = int(input_frame)
not_enough_frames[input_id].remove(int_input_frame)

그리고 not_enough_frames에서 빼야 하는 frame들만 삭제하는 코드를 실행시켰다.

그리고 결과는?

그렇다... not_enough_frames의 value가 모두 똑같은 결과가 나왔다ㅋ ㅋㅋ
왜 이런 결과가 나왔을까? 그건 not_enough_frames의 value가 모두 같은 all_frame_list를 넣어서 구성한 것이기 때문이었다.

고로 이 list들은 같은 곳을 참조하고 있었고, list의 요소를 삭제하거나 수정하면 함께 수정되는 문제가 발생했던 것이다. 이것이 얕은 복사를 했을 때 일어나는 일이다.

기본 근간이 되는 프레임 리스트는 숫자가 모두 똑같기때문에 루프를 더 돌 필요가 없어 딱 한번만 돌고 끝낸 후 그 리스트를 모두 때려박았는데 이게 문제가 됐던 것.

처음엔 왜 이런 결과가 나오는지 어디서 잘못된 건지 몰라 허둥대다 곧 얕은 복사 문제라는 걸 깨닫고 코드를 수정했다.

copy_all_frame_list = copy.deepcopy(all_frame_list)

value에 값을 넣는 for문 안에서 이런 식으로 copy.deepcopy 메소드를 이용했고 이후 버그는 일어나지 않았다.
평소에 data를 재구성할 일이 있으면 거의 습관과도 같이 deepcopy를 쓰는데 이번엔 안 써서 이런 일이...

기본에 충실하자는 생각이 든다.

profile
버그와 함께하는 삶

0개의 댓글