[파이썬] 리스트의 깊은복사는 deepcopy가 빠를까? slicing이 빠를까?

emplam27·2020년 12월 27일
9

파이썬

목록 보기
2/3
post-thumbnail

파이썬은 복사용 모듈로 copy 모듈을 제공합니다. copy 모듈에서 사용하는 대표적인 메서드는 copy와 deepcopy가 있으며 각각 얕은복사와 깊은복사 기능을 제공합니다.

여러 상황에서 깊은 복사를 해야할 일이 발생합니다. 얕은 복사는 새로운 변수에 할당해도 원본의 id값을 참조하고 있어 값을 변경하면 원본역시 값이 바뀌기 때문이죠.

파이썬의 리스트 자료형은 깊은복사의 방법에는 대표적으로 2가지가 있습니다. deepcopy를 이용하는 방법과 slicing을 이용하는 방법입니다.

1차원 리스트의 깊은복사

# deepcopy 이용
from copy import deepcopy

list_a = [i for i in range(100)]
list_b = deepcopy(list_a)


# slicing 이용
list_a = [i for i in range(100)]
list_b = list_a[:]

2차원 리스트의 깊은복사

# deepcopy 이용
from copy import deepcopy

list_a = [[i for i in range(1000)] for _ in range(1000)]
list_b = deepcopy(list_a)


# slicing 이용
list_a = [[i for i in range(1000)] for _ in range(1000)]
list_b = [item[:] for item in list_a]

처음 들었을때는 당연히 slicing이 느린 방법이라 생각했습니다만 실제로는 많이 달랐습니다. 동작시간을 비교해보기 위하여 큰 배열을 한번만 복사할때와 비교적 작은배열을 여러번 복사할때 상황을 1차원 리스트, 2차원 리스트에서 비교해 보겠습니다. 슬라이싱을 통해 복사를 진행하였을때도 deepcopy와 마찬가지로 id가 모두 다르게 생성된 것을 확인하였으니 깊은 복사가 이뤄지고 있다고 생각할 수 있겠습니다.


큰 리스트를 한번 복사할 때 시간비교

1차원 리스트

# deepcopy 이용
# time : 5.657904148101807
from copy import deepcopy

list_a = [i for i in range(10000000)]
list_b = deepcopy(list_a)


# slicing 이용
# time : 0.6562941074371338
list_a = [i for i in range(10000000)]
list_b = list_a[:]

2차원 리스트

# deepcopy 이용
# time : 0.7126703262329102
from copy import deepcopy

list_a = [[i for i in range(1000)] for _ in range(1000)]
list_b = deepcopy(list_a)


# slicing 이용
# time : 0.058615922927856445
list_a = [[i for i in range(1000)] for _ in range(1000)]
list_b = [item[:] for item in list_a]

비교적 작은 리스트를 여러번 복사할 때 시간비교

1차원 리스트

# deepcopy 이용
# time : 8.503361463546753
from copy import deepcopy

list_a = [i for i in range(100)]
list_b = []
for _ in range(1000):
    list_b = deepcopy(list_a)



# time : 0.05186152458190918
list_a = [i for i in range(100)]
list_b = []
for _ in range(100000):
    list_b = list_a[:]

2차원 리스트

# deepcopy 이용
# time : 6.350424289703369
from copy import deepcopy

list_a = [[i for i in range(100)] for _ in range(100)]
list_b = []
for _ in range(1000):
    list_b = deepcopy(list_a)



# time : 0.049834251403808594
list_a = [[i for i in range(100)] for _ in range(100)]
list_b = []
for _ in range(1000):
    list_b = [item[:] for item in list_a]

결론

리스트의 깊은복사에는 deepcopy가 많게는 100여배정도 느린 속도를 보여줍니다. deepcopy가 느린 속도를 보이는 이유를 생각해보면

  1. slicing은 리스트의 요소 갯수만큼의 시간 복잡도를 가집니다. copy모듈 안에서 여러 연산을 수행하는 것 보다 시간이 적게 소요될 수 있습니다.
  2. 모듈 import에 꽤 긴 시간이 소요될 수 있습니다.
  3. deepcopy 모듈은 객체의 모든 속성과 데이터를 복사해옵니다. 때문에 배열보다는 class객체나, dictionary같은 해쉬값을 복사해올때 이점이 있을 것 같습니다. 또한 코드를 뜯어보면 memo 속성을 넣을 수 있는데, 최적화하는데 사용할 수 있다고 합니다.

deepcopy 모듈은 굉장히 느리다고 합니다. 잠깐 검색만 해봐도 많이 느리다고 하는 결과를 볼 수 있습니다. 때문에 객체등을 복사할 때는 복사 메서드를 커스텀으로 만들어서 사용한다고 합니다.

결론적으로 배열의 깊은 복사를 사용할때는 slicing을 이용하시는걸 추천합니다.

profile
내가 다시 보고 싶은 글이어야 남들도 보고 싶은 글이라 생각하며 작성합니다. 공부한 내용들을 건강하게 공유하며 함께 성장하고자 합니다😊😊

0개의 댓글