[python] mutable과 immutable 차이점


Mutable과 Immutable 차이점

파이썬은 Call by Assignment로 모든 것이 객체이며, 속성으로 Mutable과 Immutable로 구분합니다.

Mutable 이란?

객체를 생성한 뒤, 객체의 값을 수정할 수 있습니다. 
값을 수정한다면 변수가 원래 가르키던 주소에 값을 수정합니다.

대표적으로 list, set, dict (아래 표 참고)

Immutable 이란?

객체를 생성한 뒤, 객체의 값을 수정할 수 없습니다. 
값을 수정한다면 변수가 가르키는 주소에 값을 수정하는 게 아닌, 새로운 주소에 새로운 객체를 가르킵니다. (수정X, 새롭게 할당)

대표적으로 int, float, tuple, str (아래 표 참고)


Mutable과 Immutable 비교

1. Mutable - list

x = [1, 2, 3]
y = x
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140542819770848, y id: 140542819770848 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: [1, 2, 3], y: [1, 2, 3]

x += [4, 5, 6]
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140542819770848, y id: 140542819770848 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: [1, 2, 3, 4, 5, 6], y: [1, 2, 3, 4, 5, 6]
y=x라는 구문으로 x, y는 동일한 주소(140542819770848)의 [1, 2, 3]을 가르키고 있습니다. (id 값이 동일)
x에 [4, 5, 6]을 추가하면 140542819770848 주소에 있는 값이 변경되기 때문에,
y 값을 따로 변경하지 않았어도 x와 동일한 주소 값을 참조하여 [1, 2, 3, 4, 5, 6]이 출력되는 걸 확인할 수 있습니다.


x = [1, 2, 3]
y = [1, 2, 3]
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140435814687200, y id: 140435814689760 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: [1, 2, 3], y: [1, 2, 3]

x += [4, 5, 6]
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140435814687200, y id: 140435814689760 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: [1, 2, 3, 4, 5, 6], y: [1, 2, 3]
위에서는 y=x를 통해 같은 주소값을 바라보게 했었는데요.
이번엔 x=[1, 2, 3], y=[1, 2, 3]을 각각 할당해줬습니다.  
Mutable한 객체는 같은 데이터([1, 2, 3])를 넣어도 할당되는 주소가 다른다는 점 유의해주세요.
x에 [4, 5, 6]을 추가하면 140435814687200에 있는 값이 변경되기 때문에 x는 [1, 2, 3, 4, 5, 6]이 출력되고 y는 [1, 2, 3]이 출력되는 걸 확인할 수 있습니다.

2. Mutable - set

x = {1, 2, 3}
y = x
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140520809274256, y id: 140520809274256 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: {1, 2, 3}, y: {1, 2, 3}

x |= {4, 5, 6}
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140520809274256, y id: 140520809274256 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: {1, 2, 3, 4, 5, 6}, y: {1, 2, 3, 4, 5, 6}
y=x라는 구문으로 x, y는 동일한 주소(140520809274256)의 {1, 2, 3}을 가르키고 있습니다. (id 값이 동일)
x에 {4, 5, 6}을 union하여 변경하게 되면 140520809274256 주소에 있는 값이 변경되기 때문에,
y 값을 따로 변경하지 않았어도 x와 동일한 주소 값을 참조하여 {1, 2, 3, 4, 5, 6}으로 출력됩니다.


x = {1, 2, 3}
y = {1, 2, 3}
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140497723829136, y id: 140497723827936 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: {1, 2, 3}, y: {1, 2, 3}

x |= {4, 5, 6}
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140497723829136, y id: 140497723827936 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: {1, 2, 3, 4, 5, 6}, y: {1, 2, 3}
위에서는 y=x를 통해 같은 주소값을 바라보게 했었는데요.
이번엔 x={1, 2, 3}, y={1, 2, 3}을 각각 할당해줬습니다.
Mutable한 객체는 같은 데이터({1, 2, 3})를 넣어도 할당되는 주소가 다른다는 점 유의해주세요.
x에 {4, 5, 6}을 추가하면 140497723829136에 있는 값이 변경되기 때문에 x는 {1, 2, 3, 4, 5, 6}을 출력하고 y는 {1, 2, 3}이 출력되는 걸 확인할 수 있습니다.

3. Immutable - str

x = "test"
y = x
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140590477428528, y id: 140590477428528 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: test, y: test

x += "ing"
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140590477814768, y id: 140590477428528 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: testing, y: test
y=x라는 구문으로 x, y는 동일한 주소(140590477428528)의 "test"를 가르키고 있습니다. (id 값이 동일)
x에 "ing"를 추가하면 140590477428528에 있는 값을 변경하는게 아닌, 새로운 140590477814768 주소에 "testing"이라는 값을 할당합니다. (수정 X)
그렇기 때문에 140590477428528 주소를 참조하는 y는 "test", x는 "testing"을 출력하게 됩니다.


x = "test"
y = "test"
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140716147164976, y id: 140716147164976 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: test, y: test

x += "ing"
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140716147551280, y id: 140716147164976 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: testing, y: test
위에서는 y=x를 통해 같은 주소값을 바라보게 했었는데요.
이번엔 x="test", y="test"를 각각 할당해줬습니다.
Immutable한 객체는 같은 데이터("test")를 넣어도 할당되는 주소가 같다는 점 유의해주세요.

Mutable한 객체는 같은 데이터를 넣으면 할당되는 주소가 같지만 Immutable한 객체는 다릅니다 !

Immutable한 객체는 값 수정이 되지 않기 때문에 같은 데이터에 대해 메모리를 분리할 필요가 없습니다.
Mutable한 객체는 값 수정이 가능하기 때문에 같은 데이터라도 메모리를 분리해둡니다. (A, B에 같은 데이터 할당해도 A가 변경되었을 때, B 데이터는 변경되지 않게 하기 위해, 말이 이해되지 않는 분은 위 1, 2 Mutable 예제를 다시 확인해주세요)

4. Immutable - tuple

x = (1, 2, 3)
y = x
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140525491983616, y id: 140525491983616 (주소 값 같음)
print(f"x: {x}, y: {y}")
# x: (1, 2, 3), y: (1, 2, 3)

x += (4, 5, 6)
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140525492222224, y id: 140525491983616 (주소 값 다름)
print(f"x: {x}, y: {y}")
# x: (1, 2, 3, 4, 5, 6), y: (1, 2, 3)
y=x라는 구문으로 x, y는 동일한 주소(140525491983616)의 (1, 2, 3)을 가르키고 있습니다. (id 값이 동일)
x에 (4, 5, 6)을 추가하면 140525491983616에 있는 값을 변경하는게 아닌 새로운 140525492222224 주소에 (1, 2, 3, 4, 5, 6)이라는 값을 할당합니다. (수정 X)
그렇기 때문에 140525491983616 주소를 참조하는 y는 (1, 2, 3)을, x는 (1, 2, 3, 4, 5, 6)을 출력하게 됩니다.


x = (1, 2, 3)
y = (1, 2, 3)
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140708036478288, y id: 140708036478288
print(f"x: {x}, y: {y}")
# x: (1, 2, 3), y: (1, 2, 3)

x += (4, 5, 6)
print(f"x id: {id(x)}, y id: {id(y)}")
# x id: 140708036725008, y id: 140708036478288
print(f"x: {x}, y: {y}")
# x: (1, 2, 3, 4, 5, 6), y: (1, 2, 3)
위에서는 y=x를 통해 같은 주소값을 바라보게 했었는데요.
이번엔 x=(1, 2, 3), y=(1, 2, 3)를 각각 할당해줬습니다.

Immutable한 객체는 같은 데이터((1, 2, 3))를 넣어도 할당되는 주소가 같다는 점 유의
해주세요.



최대한 쉽게 설명하고자 했지만 이해되지 않는 부분이 있거나, 내용이 잘못된 부분은 댓글 부탁드립니다.

감사합니다.


참고자료




댓글

이 블로그의 인기 게시물

[opencv-python] 이미지 크기조절(resize) 하는 법

[python]파이썬: csv reader header skip (첫번째 행 무시하기, 안읽기)

[python] selenium close와 quit 차이점