mutable (가변) 객체
-list, dictionary, set 등
-객체 생성 후 객체의 값을 바꿀 수 있음
-변수는 값이 수정된 객체를 가리키게 됨
immutable (불변) 객체
-int, float, string, tuple 등
-객체를 생성한 후 객체의 값을 바꾸는 것은 불가
-변수는 해당 값을 가진 다른 객체를 나타냄
https://webnautes.tistory.com/1181
이 블로그의 내용을 바탕으로 이해한 것 정리하려고 함.
파이썬에서 모든 것은 객체(object)이고 객체가 생성된 후 id는 변하지 않는다. id는 python에서 객체가 실제 저장된 메모리 주소를 나타낸다.
id함수를 이용하면 객체의 id를 알 수 있는데,
위의 블로거는 id 함수와 is 연산자를 통해 mutable한 객체와 immutable한 객체를 비교했다.
즉, 변수에 대입한 값을 수정한 뒤 id함수로 비교하는 것.
같으면 mutable(가변)객체, 다르면 immutable(불변)객체가 되는 것.
(값은 같을 수 있어도, 저장된 주소는 다를 수 있기 때문)
변수
변수를 새로운 객체에 대입하거나 다른 변수에 대입하는 경우에서의 mutable과 immutable 객체간 차이
1) mutable 객체_ ex. list
a = [1, 2, 3]
b = a
a is b >> True
a.append(4)
a is b >> True
#a의 값과 b의 값을 보여줌
a;b
>> [1, 2, 3, 4]
[1, 2, 3, 4]
즉, 변수 a와 a가 저장된 변수b는 같은 주소를 가리키고 있기 때문에 변수 a의 값이 변해도 주소가 바뀌지 않음.
2) immutable 객체_ ex. int
a = 1
b = a
a is b >> True
#둘은 같은 객체를 가리키고 있음
a = 2
a is b >> False
#둘은 다른 객체를 가리키고 있음
a;b
>>2
1
즉, 불변객체인 int는 변수의 값이 변하면 새로운 주소를 할당한다.
얕은복사(shallow copy)와 깊은복사(deep copy)
참고 블로그
얕은복사와 깊은복사는 객체가 다른 객체를 포함하고 있는 경우(복합객체)를 통해 잘 이해할 수 있다.
얕은복사(shallow copy)
import copy
a = [1, [1, 2, 3]]
b = copy.copy(a) # a를 얕은 복사한 것
print(b) >> [1, [1, 2, 3]]
b[0] = 100
print(b) >> [100, [1, 2, 3]]
print(a) >> [1, [1, 2, 3]]
c = copy.copy(a) # a 얕은 복사
c[1].append(4)
print(c) >> [1, [1, 2, 3, 4]]
print(a) >> [1, [1, 2, 3, 4]]
- 두번째 블록을 보면 b에서 변경된 원소가 a에는 반영되지 않는다.
반면, 세번째 블록의 경우 c에서 변경된 원소가 a에도 반영이 되었다.
- b의 수정값이 a에서 적용되지 않은 이유는
100과 1 모두 immutable객체(int)이기 때문에
값이 바뀌자마자 새로운 주소를 할당한다.
- c의 내부리스트[1, 2, 3]이 [1, 2, 3, 4]로 변경된 이유는
이 내부 객체가 mutable객체(list)이기 때문이고, mutable객체는 같은 주소를 참조한다.
- 즉, 얕은 복사는 복합객체의 틀만 복사한다. 복합객체 속의 객체
(내부리스트)은 복사하지 못한다는 것.
import copy
a = [1, [1, 2, 3]]
b = copy.deepcopy(a) #깊은 복사
b[0] = 100
b[1].append(4)
print(b) >>> [100, [1, 2, 3, 4]]
print(a) >>> [1, [1, 2, 3]]
- 깊은 복사의 경우 복합객체의 내부객체까지 모두 복사한다.
따라서, b에서 변경한 내용이 a까지 미치지 못한다.
정수 (Integer)
immutable한 객체이므로, 수정하면 새로운 객체가 생성된다.
예를 들어 1이라는 정수를 a에 대입한 값(a = 1)과 그냥 1이라는 정수는 같은 주소값(id(a) == id(1))을 가지지만**, 이 변수 a에 1을 더한 값을 다시 a에 저장하면(a = a + 1) a는 이전의 a와는 다른 새로운 객체가 되어 다른 주소값을 가진다.
** 정수 -5 ~ 256 까지는 효율성을 위해 기존 메모리에 생성되어 있는 객체를 참조한다. 따라서 a = 1 과 b = 1에서 a와 b의 주소값은 같다. 마찬가지로 변수 a에 대입한 1과 그냥 1의 주소값도 같다.
이 범위를 벗어나게 되면 새로운 주소를 할당하는데 변수에 대입되기 전까지는 같은 메모리 위치를 재사용한다.
예를 들어, 변수에 대입하지 않은 257이라는 값과 변수에 대입하지 않은 258이라는 값의 메모리 위치는 같다.
(id(257) == id(258))
257을 변수에 대입하게 되면(a = 257), 258은 다른 메모리 위치를 가진다. (id(a) != id(258))