mutable과 immutable 객체
객체 구분 표
파이썬의 객체에는 mutable과 immutable 객체가 있습니다.
| class | 설명 | 구분 |
|---|---|---|
| list | mutable 한 순서가 있는 객체 집합 | mutable |
| set | mutable 한 순서가 없는 고유한 객체 집합 | mutable |
| dict | key와 value가 맵핑된 객체, 순서 없음 | mutable |
| bool | 참,거짓 | immutable |
| int | 정수 | immutable |
| float | 실수 | immutable |
| tuple | immutable 한 순서가 있는 객체 집합 | immutable |
| str | 문자열 | immutable |
| frozenset | immutable한 set | immutable |
일반 user가 작성한 class도 대부분 mutable 한 객체 입니다.
이러한 특성은 코드의 작동방식에 영향을 미칠 수 있습니다.
다음 예제를 함께 살펴보면서 mutable한 객체와 immutable한 객체들의 특징을 알아보도록 합시다.
리스트 생성으로 살펴보는 shallow copy와 deep copy
다음 코드는 0으로 이루어진 배열을 초기화 하는 코드 입니다.
언뜻 보기엔 다를 것이 없어 보입니다.
>>> n = 2
>>> a = [[0]*n]*n
>>> b = [[0 for _ in range(n)] for _ in range(n)]
>>> print(a)
[[0, 0], [0, 0]]
>>> print(b)
[[0, 0], [0, 0]]
그러나 다음 코드를 보면 두 객체의 특성이 다르다는 것을 느끼실 수 있습니다.
>>> a[0][0] = 1
>>> print(a)
[[1, 0], [1, 0]]
>>> b[0][0] = 1
>>> print(b)
[[1, 0], [0, 0]]
이게 어떻게 된 일일까요?
분명 a는 [0][0]에 위치한 값만 변경 시켜주었는데, [1][0]의 값이 함께 변했습니다.
b의 경우는 [0][0]만 변하는 것을 확인할 수 있습니다.
이는 리스트 객체가 mutable하기 때문입니다.
mutable한 객체에 * 연산을 한다면 shallow copy로 같은 메모리를 참조하는 객체를 생성하게 됩니다.
그러므로 일반적으로 사용하는 리스트를 * 연산으로 생성하면 원치않은 결과를 만들 수 있습니다!
반면 for문으로 생성한다면 주소의 재할당이 이루어지면서 변경된 메모리 주소에 deepcopy가 이뤄지게 됩니다.
다음 코드를 통해서 실제로 할당된 주소값을 확인할 수 있습니다.
>>> print(id(a[0]))
22828396204544
>>> print(id(a[1]))
22828396204544
>>> print(id(b[0]))
22828394826368
>>> print(id(b[1]))
22828395304128
참고 문헌
또 다른 예시는 다음 페이지에서 확인하실 수 있습니다.
https://wikidocs.net/16038
댓글남기기