파이썬의 객체는 크게 두 가지 종류로 나눌 수 있다.
mutable(값이 변하는 객체)와 immutable(값이 변하지 않는 객체)이다. 이를테면 list, dict 등은 특정 값을 넣고 빼고 할 수 있으므로 mutable하다고 할 수 있지만, str이나 tuple과 같은 경우 수정 자체가 불가능하기 때문에 immutable한 객체라고 부를 수 있다.
mutable과 immutable을 이해하면 객체의 복사에 대한 개념이나 또는 함수에서 변수가 매개변수로써 전달될 때 기존의 입력 변수값이 변경되는지 등을 파악하는 데 충분히 도움이 된다. 따라서 코딩해보면서 익숙해지는 것이 좋다.
실험 코드를 작성해보겠다.
# mutable 예시
a = ['a']
c = ['a']
print(id(a))
print(id(c))
>>2646997146176
>>2646997141952
list의 경우 mutable한 객체이다. 같은 원소의 리스트라도 할당될 때마다 다른 주소값을 가진다.
# immutable 예시
a = 'a'
c = 'a'
print(id(a))
print(id(c))
>>140720624684256
>>140720624684256
str은 immutable한 객체이다. 이 경우 같은 값을 할당했는데 list와 다르게 같은 주소값을 가진다.
우리는 이 실험에서 'a'라는 문자열은 특정 메모리에 고정적으로 할당된 것이라고 생각할 수 있다. 반면, list는 실행할 때마다 메모리에 추가적으로 할당되는 것이다.
python의 list가 linked list인 것을 생각하면 충분히 이해가 가는 것이, array list 구조가 아니기 때문에 위치가 고정되지 않는 것이다.
참조와 복사에 대해서도 재미있는 실험을 할 수 있었다. 이에 대해서 포스팅해두었다.
a = 'a'
c = a
print(id(a))
print(id(c))
>>140720624684256
>>140720624684256
단순히 참조 복사만 진행한다면 c는 'a'의 메모리 주소를 참조하기에 같은 a와 c는 동일하게 'a'가 속해있는 메모리 주소 id를 가진다. 하지만 얕은 복사인 .copy()는 지원되지 않는다.
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[58], line 4
1 # list는 mutable
3 a = 'a'
----> 4 c = a.copy()
6 print(id(a))
7 print(id(c))
AttributeError: 'str' object has no attribute 'copy'
이렇듯 'copy()' 메소드는 mutable 객체의 얕은 복사를 지원하는 데에만 사용된다. 이유를 생각해보자. python에서 immutable한 객체는 얕은 복사나 깊은 복사의 필요성이 없는데, 한번 생성되면 그 상태를 변경할 수 없기 때문이다.
반면, mutable한 객체는 복사본을 만들 시 단순히 참조하는 것만으로는 충분하지 않다. 하나의 변수를 통해 객체를 수정하면 다른 모든 참조도 그 변경을 반영하기 때문에 사용자가 원하지 않는 상황이 발생할 수 있다(사실 필자도 이런 부분에서 해당 개념에 대해 공부의 필요성을 느꼈다).
결론적으로 copy() 메소드는 mutable 객체의 얕은 복사(shallow copy)를 만들어주며, 이는 원본 객체의 최상위 레벨만 복사하는 것이므로, 내부에 또 다른 객체가 있을 경우 그 객체만 참조한다.
a = ['a']
c = a.copy()
print(id(a)) # ['a']
print(id(c)) # 얕은 복사
print()
print(id(a[0])) # 'a'
print(id(c[0])) # 얕은 복사 내 객체
# list의 id는 다름. 즉, 새로운 memory에 생성된 것.
>>2646997613568
>>2646997684736
# list 내 객체는 참조
>>140720624684256
>>140720624684256
Reference
https://wikidocs.net/91520