파이썬에서 배열을 복사하려면 어떻게 해야 할까?
arr = [1, 2, 3, 4]
arr2 = arr
print(arr)
print(arr2)
위와 같이 작성하면 될 것 같다.
실제로 출력 해보면 같은 값이 출력된다.
하지만 위의 방법에는 문제가 있다.
💣 파이썬 배열 복사의 문제점
위의 출력 결과는 배열이 복사된 것 처럼 보인다.
arr = [1, 2, 3, 4]
arr2 = arr
arr2.append(5)
print(arr)
print(arr2)
만약, 기존 배열을 복사하여 원소 하나만 추가하고 싶다면 위와 같이 작성할 것이다.
하지만 위 코드의 출력 결과는 아래와 같다.
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
arr2를 바꾸기를 원했지만 arr도 함께 변경된다.
변수를 생성하고 값을 할당한다는 것은 JS를 공부하며 배웠듯이 변수는 값의 주소를 저장하는 것이다.
다시 말해 변수는 해당 주소를 통해 값이 저장되어 있는 메모리에 접근하여 값을 참조하는 것이다.
arr = [1, 2, 3, 4]
arr2 = arr
print(id(arr))
print(id(arr2))
# 1629144040320
# 1629144040320
두 변수의 메모리 주소가 같다.
결론적으로 우리가 의도했던 값의 복사가 아니라 주소의 복사가 수행된 것이다.
같은 주소를 참조하기 때문에 한 군데서 값을 수정하면 다른 변수에도 영향을 미치게 된다.
🎉 copy
위의 문제점을 해결하기 위해 copy를 사용할 수 있다.
arr = [1, 2, 3, 4]
arr2 = arr.copy()
arr2.append(5)
print(arr)
print(arr2)
# [1, 2, 3, 4]
# [1, 2, 3, 4, 5]
의도한 대로 arr2의 값만 변경되었다.
arr = [1, 2, 3, 4]
arr2 = arr.copy()
arr2.append(5)
print(id(arr))
print(id(arr2))
# 2855259227008
# 2855259320256
메모리 주소를 확인해보면 둘의 값이 다른 것을 확인할 수 있다.
두 변수가 가리키는 메모리 주소가 다르기 때문에 특정 메모리에 위치한 값이 바뀌더라도 다른 변수에 영향을 미치지 않게 된다.
이와 같이 copy를 이용해 복사하는 것을 " 얕은 복사 "라고 한다.
왜 얕은 복사라고 부르는 것일까?
arr = [[1, 2, 3], [4, 5, 6]]
arr2 = arr.copy()
arr2[0][0] = 0
print(arr)
print(arr2)
# [[0, 2, 3], [4, 5, 6]]
# [[0, 2, 3], [4, 5, 6]]
우리가 의도한 것은 복사한 arr2 배열의 첫 원소를 0으로 바꾸는 것이다.
하지만 copy를 사용했음에도 arr2에 의해 arr도 함께 변경되었다.
arr = [[1, 2, 3], [4, 5, 6]]
arr2 = arr.copy()
arr2[0][0] = 0
print(id(arr))
print(id(arr2))
print()
print(id(arr[0]))
print(id(arr2[0]))
# 1455052476224
# 1455052404672
#
# 1455051391872
# 1455051391872
중첩된 리스트의 주소는 그대로 가지고 있다는 것을 확인할 수 있다.
따라서 copy를 이용한 리스트의 복사는 얕은 복사라고 할 수 있다.
✨ deepcopy
위의 문제점을 해결하기 위해서는 내부에 있는 것들도 새로운 메모리에 저장하여 독립적으로 만들어야 한다.
이때 사용하는 것이 deepcopy이다.
deepcopy는 copy와 다르게 copy 모듈을 import하여 사용해야 한다.
import copy
arr = [[1, 2, 3], [4, 5, 6]]
arr2 = copy.deepcopy(arr)
arr2[0][0] = 0
print(arr)
print(arr2)
# [[1, 2, 3], [4, 5, 6]]
# [[0, 2, 3], [4, 5, 6]]
의도한대로 arr2의 첫 원소만 바꿀 수 있다.
import copy
arr = [[1, 2, 3], [4, 5, 6]]
arr2 = copy.deepcopy(arr)
arr2[0][0] = 0
print(id(arr))
print(id(arr2))
print()
print(id(arr[0]))
print(id(arr2[0]))
# 2609336405504
# 2609336406784
#
# 2609336588992
# 2609336406912
메모리 주소를 확인해보면 중첩된 리스트도 새로운 메모리 주소에 복사 되었음을 확인할 수 있다.
이처럼 내부의 것들도 모두 새로운 주소로 copy하기 때문에 deepcopy는 " 깊은 복사 "라고 한다.
'개발 > TMI' 카테고리의 다른 글
[Next.js13] middleware 사용법 (0) | 2023.08.16 |
---|---|
[TypeScript + Jest] TypeScript 프로젝트 시작 + Jest 적용 (0) | 2023.08.06 |
[SvelteKit] 스벨트 킷에 테일윈드CSS 적용하기 (SvelteKit + tailwindCSS) (0) | 2023.03.13 |
제2회 너디너리 (Ne(O)rdinary) 해커톤 후기 (0) | 2022.09.26 |