깊은 복사를 사용하기 위해서는 copy 모듈의 deepcopy 함수를 사용해야 한다.
깊은 복사는 리스트 내부 리스트, 딕셔너리 내부 리스트 등 내부에 있는 객체 모두 새롭게 만들어주는 작업을 한다.
모든 것 다 새롭게 복사.
그냥 독립적이 되어버림.
import copy # copy 모듈 불러오기
print('=' * 50)
arr1 = [1, 2, [99, 88, 77], 3]
arr2 = copy.deepcopy(arr1) # copy 모듈 깊은 복사
print("1. 전체 출력")
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
print("\n2. 리스트에 새 key, value 추가")
arr1.append(0)
print('arr1.append(0)')
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
# 리스트 내부에 리스트 추가
print("\n3. 리스트 내부 리스트.")
print(f"arr1[2] : {arr1[2]}, address : {hex(id(arr1[2]))}")
print(f"arr2[2] : {arr2[2]}, address : {hex(id(arr2[2]))}")
print("\n4. 리스트 내부 리스트에 값 추가")
arr1[2].append(10)
print("arr1[2].append(10)")
print(f"arr1[2] : {arr1[2]}, address : {hex(id(arr1[2]))}")
print(f"arr2[2] : {arr2[2]}, address : {hex(id(arr2[2]))}")
print("\n5. 리스트 전체 다시 확인")
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
python deepcopy
1 번 전체 출력을 보면arr1, arr2의 주소 값이 다른 것을 볼 수 있다.
3번의 리스트 내부 리스트도 보면 이전에 얕은 복사와 달리 arr1[2], arr2[2] 의 [99, 88, 77]인 리스트 내부 리스트도 주소 값이 다른 것을 볼 수 있다.
그래서 4번에서 리스트 내부 리스트인 arr1[2]에 값을 추가해도 arr2[2]에는 전혀 영향이 없는 것 을 알 수 있다.
print('=' * 50)
arr1 = [1, 2, 3]
arr2 = arr1[:] # copy 모듈 깊은 복사
print("1. 1차원 리스트")
print("1-1. 전체 출력")
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
print("\n1-2. 리스트에 새 key, value 추가")
arr1.append(0)
print('arr1.append(0)')
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
print('=' * 50)
arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
arr2 = [item[:] for item in arr1]
print("2. 2차원 리스트")
print("2-1. 전체 출력")
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
print("\n2-2. 리스트에 새 key, value 추가")
arr1[0].append(0)
print('arr1.append(0)')
print(f'arr1 : {arr1}, address : {hex(id(arr1))}')
print(f'arr2 : {arr2}, address : {hex(id(arr2))}')
위에 얕은 복사에서 슬라이싱을 이용했을 때에는 깊은 복사라고 하기에도, 얕은 복사라고 하기에도 애매하다고 했다.
그렇지만 얕은 복사였다.
하지만 1차원 리스트 내에 다른 리스트가 존재하지 않는다면, immutable 타입들만 들어가있다면, 이것 또한 깊은 복사라고 할 수 있다.
2차원 리스트도 마찬가지이다.
2차원 리스트 내의 있는 리스트들 안에 immutable 타입들로만 구성되어 있다면?
그렇다면 이것 또한 slicing을 통해 깊은 복사를 구현할 수 있다.
리스트의 깊은복사에는 deepcopy가 많게는 100여배정도 느린 속도를 보여준다.
deepcopy가 느린 속도를 보이는 이유를 생각해보면
slicing
은 리스트의 요소 갯수만큼의 시간 복잡도를 가진다. copy모듈 안에서 여러 연산을 수행하는 것 보다 시간이 적게 소요될 수 있다.import
에 꽤 긴 시간이 소요될 수 있다.deepcopy
모듈은 객체의 모든 속성과 데이터를 복사해온다. 때문에 배열보다는 class
객체나, dictionary
같은 해쉬값을 복사해올때 이점이 있을 것 같다. 또한 코드를 뜯어보면 memo
속성을 넣을 수 있는데, 최적화하는데 사용할 수 있다고 한다.deepcopy
모듈은 굉장히 느리다고 한다. 잠깐 검색만 해봐도 많이 느리다고 하는 결과를 볼 수 있다.
때문에 객체등을 복사할 때는 복사 메서드를 커스텀으로 만들어서 사용한다고 한다.
결론적으로 배열의 깊은 복사를 사용할때는 slicing
을 이용하시는걸 추천한다.
즉, 복사한 이후부터는 '독립적이다.' '둘이 쌩깠다.' '이젠 아무 사이도 아니다.'인 상태가 "깊은 복사"인 것이다.