-
[CS study] 2022.06.13CS 2022. 6. 13. 20:30
파이썬 얕은 복사, 깊은 복사
mutable, immutable 객체에 대해 먼저 알아야 함
immutable
변경 불가능한 객체 (일반적인 자료형, int, string, tuple)
# Int a = 1 print(id(a)) #4346364144 a += 1 print(id(a)) #4346364176 # String a = 'a' print(id(a)) #4304480688 a += 'b' print(id(a)) #4304389296 # Tuple a = (1,2) print(id(a)) #4343623232 a += (3,) print(id(a)) #4343656000immutable 객체들은 값이 변경될때 객체가 변하는 것을 확인 할 수 있다.
여기에 속한 객체들은 call by value의 속성을 띄고있다.
# Int a = 1 b = a print(a == b) # True b += 1 print(a == b) # False # String a = 'a' b = a print(a == b) # True b += 'b' print(a == b) #False # Tuple a = (1,2) b = a print(a == b) # True b += (3,) print(a == b) # Falseimmutable 객체들은 값이 변경되는것이 새로운 객체로 생성되는 것이다.
변경이 일어날 때 기존 객체는 변하지 않는다.
mutable
변경 가능한 객체 (list, dict, set)
# List a = [1,2] print(id(a)) #4335710848 a.append(3) print(id(a)) #4335710848 # Dict a = {1:'a'} print(id(a)) #4340089920 a[2] = 'b' print(id(a)) #4340089920mutable 객체들은 값이 변경될 때 객체의 값이 변경되는것을 확인 할 수 있다.
여기에 속한 객체들은 call by reference 속성을 가지고 있다.
# List a= [1,2] b = a print(a == b) # True b.append(3) print(a == b) # True # Dict a = {1:'a'} b = a print(a == b) # True b[2] = 'b' print(a == b) # True얕은 복사 ([:], copy, copy.copy)
- 변수를 복사했다고 생각했지만 실제로는 연결되어있는 것을 의미함
- 변수를 복사 했지만 참조한 곳은 동일하기 때문에 같은 변수를 가리키고 있는 것
예시
# 얕은 복사 arr1 = [1,2] arr2 = arr1 arr1.append(3) print(arr1) # [1,2,3] print(arr2) # [1,2,3]- 변수를 복사했다고 생각했지만 사실 복사한 것은 메모리 주소만 복사한 것 실제 객체를 복사한 것이 아니다.
- 그렇기 때문에 append를 이용해 값을 추가했을때 arr2에도 동일하게 적용이 되는 것이다.
- 이렇게 복사를 했음에도 값을 변경하면 다른 변수에도 영향을 끼치도록 참조만 복사한 것을 얕은 복사라고 함
- immutable 객체들은 얕은 복사를 하던 깊은 복사를 하던 사실 상관이 없음 값이 변경되면 무조건 참조가 변경되기 때문이다.
- 즉 파이썬에서 얕은 복사 깊은 복사를 구분하고 학습해야하는 객체는 mutable 객체들이다.
mutable 객체의 얕은 복사 방법 4가지
1. '=' 대입 연산자를 이용한 얕은 복사 (위 예시와 같이 '='로 복사)
2. [:] 슬라이싱을 이용한 얕은 복사 (눈속임)
arr1 = [1,2,3,[4,5,6]] arr2 = arr1[:] # 복사 # 메모리 주소가 다르다 깊은 복사 아닌가? print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6]] 4315672384 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6]] 4315704448 # 값이 다름 깊은 복사 아닌가? arr2.append(32) print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6]] 4315672384 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6], 32] 4315704448 # 리스트 안에 리스트 가르키고있는 주소가 같다 얕은 복사! print(arr1[3], id(arr1[3])) # [4, 5, 6] 4315099776 print(arr2[3], id(arr2[3])) # [4, 5, 6] 4315099776 # 리스트 안에 리스트에 값 추가 arr1[3].append(64) print(arr1[3], id(arr1[3])) # [4, 5, 6, 64] 4315099776 print(arr2[3], id(arr2[3])) # [4, 5, 6, 64] 4315099776 # 전체 다시 확인 내부적으로 보면 앝은 복사이다! print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6, 64]] 4315672384 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6, 64], 32] 4315704448 # 겉에 있는 리스트만 새롭게 객체를 추가했지만 사실 내부에 있는 리스트 요소는 하나의 [4,5,6] 리스트를 가리키고있음 # 완전한 깊은 복사도 아니고 완전한 얕은 복사도 아니지만 이것 또한 얕은 복사로 구분한다.3. copy 메서드 이용한 얕은 복사 (객체에 제공)
# 위 예시와 동일 arr1 = [1,2,3,[4,5,6]] arr2 = arr1.copy() # 복사 copy 메서드 이용4. copy 모듈의 copy 함수를 이용한 얕은 복사 (딕셔너리 얕은 복사)
import copy dict1 = {'a': 'rookie', 'b': [1,2,3]} dict2 = copy.copy(dict1) print(dict1, id(dict1)) # {'a': 'rookie', 'b': [1, 2, 3]} 433311033 print(dict2, id(dict2)) # {'a': 'rookie', 'b': [1, 2, 3]} 4333110592 # 새 key, value 추가 dict2['c'] = '루키쉐' print(dict1, id(dict1)) # {'a': 'rookie', 'b': [1, 2, 3]} 4333110336 print(dict2, id(dict2)) # {'a': 'rookie', 'b': [1, 2, 3], 'c': '루키쉐'} 4333110592 # 딕셔너리 내부 리스트 print(dict1['b'], id(dict1['b'])) # [1, 2, 3] 4333439808 print(dict2['b'], id(dict2['b'])) # [1, 2, 3] 4333439808 # 내부 리스트에 값 추가 dict1['b'].append('no') print(dict1['b'], id(dict1['b'])) # [1, 2, 3, 'no'] 4333439808 print(dict2['b'], id(dict2['b'])) # [1, 2, 3, 'no'] 4333439808 # 전체 다시 확인 print(dict1, id(dict1)) # {'a': 'rookie', 'b': [1, 2, 3, 'no']} 4333110336 print(dict2, id(dict2)) # {'a': 'rookie', 'b': [1, 2, 3, 'no'], 'c': '루키쉐'} 4333110592 # key, value를 추가했을때 보면 깊은 복사 같다. # 내부 리스트를 보면 주소가 동일한 것을 볼수 있고 내부 리스트에 값을 추가하면 둘다 추가되는 것을 확인 가능 얕은복사깊은 복사 (copy.deepcopy)
- 깊은 복사를 사용하기 위해서는 copy 모듈의 deepcopy 함수를 사용해야함
- 리스트 내부 리스트, 딕셔너리 내부 리스트 등 내부에 있는 객체를 모두 새롭게 만들어 주는 작업이다.
- 모든 것을 다 새롭게 복사 독립적이게 됨
import copy arr1 = [1,2,3,[4,5,6]] arr2 = copy.deepcopy(arr1) # 복사 # 메모리 주소가 다르다 깊은 복사 print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6]] 4367780608 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6]] 4367785152 # 값이 다름 arr2.append(32) print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6]] 4367780608 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6], 32] 4367785152 # 리스트 안에 리스트 들의 주소가 다르다! print(arr1[3], id(arr1[3])) # [4, 5, 6] 4367780288 print(arr2[3], id(arr2[3])) # [4, 5, 6] 4367780736 # 리스트 안에 리스트에 값 추가 주소가 달라서 arr2에 영향을 주지 않음 arr1[3].append(64) print(arr1[3], id(arr1[3])) # [4, 5, 6, 64] 4367780288 print(arr2[3], id(arr2[3])) # [4, 5, 6] 4367780736 # 전체 다시 확인 독립적이다 깊은 복사 print(arr1, id(arr1)) # [1, 2, 3, [4, 5, 6, 64]] 4367780608 print(arr2, id(arr2)) # [1, 2, 3, [4, 5, 6], 32] 4367785152'CS' 카테고리의 다른 글
[CS study] 2022.06.29 (0) 2022.06.29 [CS study] 2022.06.17 (0) 2022.06.17 [CS study] 2022.06.08 (0) 2022.06.08 [CS study] 2022.06.01 (0) 2022.06.01 [CS study] 2022.05.30 (0) 2022.05.31