본문 바로가기
Python/기초

[파이썬/Python] immutable과 mutable 객체

by 모두의 케빈 2023. 7. 4.

immutable과 mutable 객체, 왜 알아야 하나요?


 

코딩을 공부하시다 보면, 깊은 복사와 얕은 복사에 대한 개념을 종종 접할 때가 있습니다. 이 개념에 대해 모르고 사용하시는 분들도 많으신데요. 평소에는 크게 문제가 되지 않지만, 간혹 얕은 복사가 필요할 때 깊은 복사를 하거나 그 거꾸로인 경우로 인해 코드의 결과값이 달라지는 경우가 생깁니다.

별다른 에러 메시지가 나오지 않기 때문에, 이 개념을 모르신다면 관련 에러를 디버깅하는데 어려움을 겪을 수 있습니다. 물론 파이썬을 공부하는 입장에서는 당연히 기초를 튼튼히 한다는 생각으로 공부하시면 좋을 것 같습니다.

얕은 복사와 깊은 복사에 대해서는 다음 시간에 상세하게 설명드리겠습니다. 이번 시간에는 근간이 되는 immutable, mutable 객체에 대해 배워 보도록 하겠습니다.

 

 

immutable: 변할 수 없는, 불변의


immutable 객체는 값이 바뀌면 새로운 객체를 생성한다.

 

파이썬은 객체 지향 언어이므로 모든 개념은 객체로 표현됩니다. 모든 객체는 기본적으로 3가지 개념을 갖습니다. 첫 번째는 주소값입니다. 그 객체를 고유하게 식별해 주는 값이라고 할 수 있습니다.

a = 100

print("a의 identity: {}".format(id(a)))
# a의 identity: 140707115512704

 

두 번째는 객체의 타입입니다. 객체가 어떤 유형에 속하는지 확인할 수 있습니다.

a = 100

print("a의 type: {}".format(type(a)))
# a의 type: <class 'int'>

 

마지막은 값(Vaule)입니다. 어떤 객체를 선언했을 때, 값이 바뀌면 mutable이고 바뀌지 않으면 immutable 객체라고 합니다. immutable 객체의 값은 바뀔 수 없기 때문에 값을 바꾸려면 새로운 객체를 생성해야 합니다.

immutable 변수에는 자주 사용하는 정수(int), 문자열(str)과 같은 자료 유형과 tuple 등이 해당됩니다. 정수가 불변의 객체라고 하는 점이 잘 이해가 안 가실 수 있습니다. 아래의 예시를 보겠습니다.

a = 100
print("a의 identity: {}".format(id(a)))

b = 100
print("b의 identity: {}".format(id(b)))

# a의 identity: 140707115512704
# b의 identity: 140707115512704

 

a와 b는 다른 변수인데, 주소값이 같은 것을 볼 수 있습니다. 파이썬에서는 자주 사용되는 정수(-5~256)를 프로그램 시작과 함께 메모리에 자동 할당하고, 같은 값을 가리키는 변수의 주소값들은 한 곳에 바인딩하기 때문인데요. '정수 100'이라는 객체에 a와 b의 주소값이 바인딩되었다고 생각하시면 됩니다.

중요한 것은 immutable 객체 특성상, 값이 동일하면 같은 주소값을 가져야 하기 때문에 '정수 100'이라는 객체는 그 주소값이 변하지 않는다는 점입니다.

 

이는 문자열의 경우도 마찬가지입니다. 아래 코드를 보면 a와 b가 같은 주소값을 갖는 것을 보실 수 있습니다.

a = 'Immutable'
print("a의 identity: {}".format(id(a)))

b = 'Immutable'
print("b의 identity: {}".format(id(b)))

# a의 identity: 1829939728624
# b의 identity: 1829939728624

 

 

그러나, 이는 꼭 100% 맞지는 않습니다. immutable 객체이지만 값이 커지거나 복잡해지면 같은 값을 같더라도 다른 값으로 인식하여 새로운 객체를 생성하는 경우가 생깁니다. (원래 정의대로라면 값이 같다면 새로운 객체를 생성할 필요는 없습니다.

아래 코드를 보겠습니다. 문자열이 길어지니, 서로 다른 값이라고 인식하여 객체를 새롭게 할당하기 때문에 주소값이 달라진 것을 확인할 수 있습니다.

a = 'Immutable_변수_Test'
print("a의 identity: {}".format(id(a)))

b = 'Immutable_변수_Test'
print("b의 identity: {}".format(id(b)))

# a의 identity: 1829939384112
# b의 identity: 1829939383088

 

이는 정수형도 동일합니다. 파이썬에서는 [-5, 256] 범위를 초과하는 정수는 값이 같더라도 다른 객체로 인식하여 새롭게 객체를 생성합니다.

a = 45789
print("a의 identity: {}".format(id(a)))

b = 45789
print("b의 identity: {}".format(id(b)))

# a의 identity: 1829939616080
# b의 identity: 1829939616176

 

따라서 요약하자면, 이론 상 immutable 객체는 선언되면 값이 바뀔 수 없기 때문에 같은 값의 객체는 같은 주소값을 가져야 하지만 값이 커지거나 복잡해지면 꼭 이런 규칙이 맞지는 않는다고 볼 수 있겠네요.

 

 

mutable: 변할 수 있는


mutable 객체는 선언된 이후 값을 바꿀 수 있습니다.

 

mutable 객체는 한번 선언되더라도 그 안의 값을 바꿀 수 있습니다. 대표적으로는 list와 dict 자료 유형이 있는데요. 실제 코드를 보면서 설명드리겠습니다.

a = [2]
print("a의 identity: {}, 값: {}".format(id(a), a))

a.append(3)
print("a의 identity: {}, 값: {}".format(id(a), a))

# a의 identity: 1829939285888, 값: [2]
# a의 identity: 1829939285888, 값: [2, 3]

 

위의 코드를 보시면 a를 선언한 다음 a의 값을 [2]에서 [2,3]으로 바꿨지만 주소값이 동일한 것을 확인할 수 있습니다. 이는 '182993928588' 메모리에 있는 객체 안의 값을 바꿨다고 볼 수 있는데요. 이러한 개념이 바로 mutable 객체입니다.

 

다음 시간에는 깊은 복사와 얕은 복사에 대해 알아보도록 하겠습니다.

댓글