파이썬은 복사용 모듈로 copy 모듈을 제공합니다. copy 모듈에서 사용하는 대표적인 메서드는 copy와 deepcopy가 있으며 각각 얕은복사와 깊은복사 기능을 제공합니다.
여러 상황에서 깊은 복사를 해야할 일이 발생합니다. 얕은 복사는 새로운 변수에 할당해도 원본의 id값을 참조하고 있어 값을 변경하면 원본역시 값이 바뀌기 때문이죠.
파이썬의 리스트 자료형은 깊은복사의 방법에는 대표적으로 2가지가 있습니다. deepcopy
를 이용하는 방법과 slicing
을 이용하는 방법입니다.
# 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[:]
# 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
가 모두 다르게 생성된 것을 확인하였으니 깊은 복사가 이뤄지고 있다고 생각할 수 있겠습니다.
# 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[:]
# 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]
# 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[:]
# 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
가 느린 속도를 보이는 이유를 생각해보면
slicing
은 리스트의 요소 갯수만큼의 시간 복잡도를 가집니다. copy모듈 안에서 여러 연산을 수행하는 것 보다 시간이 적게 소요될 수 있습니다.import
에 꽤 긴 시간이 소요될 수 있습니다. deepcopy
모듈은 객체의 모든 속성과 데이터를 복사해옵니다. 때문에 배열보다는 class
객체나, dictionary
같은 해쉬값을 복사해올때 이점이 있을 것 같습니다. 또한 코드를 뜯어보면 memo
속성을 넣을 수 있는데, 최적화하는데 사용할 수 있다고 합니다.deepcopy
모듈은 굉장히 느리다고 합니다. 잠깐 검색만 해봐도 많이 느리다고 하는 결과를 볼 수 있습니다. 때문에 객체등을 복사할 때는 복사 메서드를 커스텀으로 만들어서 사용한다고 합니다.
결론적으로 배열의 깊은 복사를 사용할때는 slicing
을 이용하시는걸 추천합니다.