COPY, 얕은 복사와 깊은 복사 - Python

2023. 7. 16. 00:01카테고리 없음

예전에 정리를 하고 넘어갔었는 데, 오랜만에 알고리즘을 공부하다 보니 개념에 구멍이 생겨서 정리해보고자 한다!

 

해당 내용을 알기 전에 먼저 mutable, immutable에 대해 알아야한다. 

mutable : 변할 수 있다.

immutable : 변할 수 없다.

즉 mutable인 변수는 수정이 가능하고, immutable인 변수는 수정이 불가능 하다는 소리. 예시를 들어 살펴보자

a = 1
b = a
print(id(a), id(b))
b = 2
print(id(a), id(b))
print(a, b)
4301252912 4301252912
4301252912 4301252944
1 2

 

해당 예시를 살펴보면 처음 a, b는 id가 같다. 즉 같은 객체를 가르키고 있었다. 하지만 b = 2를 대입하면 a, b의 id가 달라진다. 즉 객체의 값을 수정한 게 아니라 새로운 객체를 생성해 대입함을 알 수 있다. 이는 integer가 immutable이기에 수정이 불가능하여 새로운 객체를 생성했다는 것을 알 수 있다. 그렇다면 mutable의 예시도 살펴보자. mutable의 대표적인 예는 list가 있다.

 

a = [1, 2, 3]
b = a
print(id(a), id(b))
print(id(a[1]), id(b[1]))
b[1] = 0
print(id(a), id(b))
print(id(a[1]), id(b[1]))
print(a, b)
4343840128 4343840128
4342475088 4342475088
4343840128 4343840128
4342475024 4342475024
[1, 0, 3] [1, 0, 3]

결과를 살펴보면 a, b의 id와 값이 같다는 것을 알 수 있다. 즉 list 객체는 mutable하기에 새로운 list 객체를 생성한 것이 아니라, 기존 객체를 수정함을 알 수 있다. 또한 list 객체 안에는 integer 객체가 들었다. integer객체는 immutable하기에 값을 바꾸어 주니 id 가 변했다는 것을 알 수 있다. 즉 list는 mutable하다고 list안의 객체들까지 mutable로 취급되지 않는다.

 

참고로 list, set, dict가 mutable 하고 그 외에는 immutable하다!

 

자 그럼 copy를 살펴보자.

 

 

복사에는 얕은 복사깊은 복사가 있다. 두 경우 모두 일반적인 경우에서는 객체가 구분될 수 있도록 복사한다. 하지만 이중 list와 같이 mutable 객체 안에 mutable객체가 존재할 때 차이가 발생한다.

 

먼저 얕은 복사란 말 그대로 얕게 복사하는 것이다. 즉 첫번째 list만 복사가 되고 내부 list는 복사되지 않는다. 예시를 보면서 생각해보자.

a = [[1], [2], [3]]
b = copy.copy(a)
print("외부 list의 id",id(a), id(b))
print("내부 list의 id", id(a[1]), id(b[1]))
b[1][0] = 0
print("내부 list의 id", id(a[1]), id(b[1]))
print(a, b)
외부 list의 id 4367434752 4367435392
내부 list의 id 4367258752 4367258752
내부 list의 id 4367258752 4367258752
[[1], [0], [3]] [[1], [0], [3]]

결과를 살펴보면 외부 list의 id는 다르게 나오지만, 내부 list의 id는 서로 같다. 즉 외부 list는 구분이 되지만 내부 list은 같은 객체라는 의미이다. 따라서 copy함수(얕은 복사)를 사용하면 같은 내부 list 객체를 가지게 된다. 즉 b의 내부 list를 수정한다면 a, b 모두 바뀌게 된다.

 

 

깊은 복사인 경우는 내부의 list 객체도 정상적으로 복사한다.

a = [[1], [2], [3]]
b = copy.deepcopy(a)
print("외부 list의 id",id(a), id(b))
print("내부 list의 id", id(a[1]), id(b[1]))
b[1][0] = 0
print("내부 list의 id", id(a[1]), id(b[1]))
print(a, b)
외부 list의 id 4305323008 4305323648
내부 list의 id 4305147008 4305322752
내부 list의 id 4305147008 4305322752
[[1], [2], [3]] [[1], [0], [3]]

외부, 내부 list들의 id가 모두 다르다는 것과 값 또한 다르게 출력됨을 확인 할 수 있다. 

 

 

즉, 다중 list와 같이 여러 mutable 객체가 상황에서 서로 구분되도록 복사하고 싶다면 deepcopy 즉 깊은 복사를 사용하자~ 그 외에는 굳이 깊은 복사를 사용할 필요가 없다!