id() 함수를 통한
mutable 객체와 immutable 객체 비교
mutable 객체는 생성 후에도 변경이 가능한 객체이며, 수정 가능한 특징을 지녔다.(list, dict, set, 사용자 정의 클래스)
immutable 객체는 생성 후에 변경이 불가능하며, 값을 변경하려면 새로운 객체를 생성해야 하는 특징을 지녔다.(int, float. str, tuple, bytes)
비교보기
# immutable 객체: int
a = 10
print("a의 id:", id(a)) # 예: 140732497872016
a += 1 # 새로운 객체가 생성됨
print("a의 id after += 1:", id(a)) # 새로운 id
# immutable 객체: str
s = "hello"
print("s의 id:", id(s))
s += " world" # 새로운 문자열 객체 생성
print("s의 id after += ' world':", id(s))
# mutable 객체: list
lst = [1, 2, 3]
print("lst의 id:", id(lst))
lst.append(4) # 같은 리스트 객체 내에서 값만 변경
print("lst의 id after append:", id(lst))
# mutable 객체: dict
d = {"a": 1}
print("d의 id:", id(d))
d["b"] = 2 # 딕셔너리 안의 값만 변경
print("d의 id after adding key:", id(d))
id() 함수를 통해 주소값을 본다면, mutable 객체는 수정 후에도 같은 주소값을 지니고 있는 것을 볼 수 있지만,
immutable 객체는 수정 후에는 주소값이 변경되어 있음을 확인 할 수 있다.
할당(대입)
할당 또는 대입이라고 표현하며 내부 메모리에 같은 주소값을 공유하고 있다.
이것은 복사가 아닌 동일한 객체를 가르키고 있다는 표현이 맞을 것이다.
예시 보기
a = [1, 2, 3]
b = a # 그냥 a를 b에 할당
b[0] = 999
print(a) # [999, 2, 3] → a도 같이 바뀜

얕은 복사(shallow copy)
원본 객체의 내용을 새로운 객체로 복사하는 것을 의미한다.
하지만 내부의 객체는 동일한 객체를 참조한다.
슬라이스 또는 copy 모듈의 copy() 메서드를 통해 얕은 복사를 실행할 수 있다.
예시 보기
import copy
# 슬라이싱 활용
a = [[1, 2], [3, 4]]
b = a[:] # 얕은 복사
b[0][0] = 999
print(a) # [[999, 2], [3, 4]] → 내부 리스트는 공유됨
# copy 활용
a = [[1, 2], [3, 4]]
b = copy.copy(a) # 얕은 복사
b[0][0] = 888
print(a) # [[888, 2], [3, 4]] → 동일

깊은 복사(deep copy)
원본 객체의 내용을 새로운 객체로 복사하는 것, 내부에 있는 객체들도 모두 새로이 생성 하여 복사한다.
원본 객체와 복사본 객체는 독립된 객체로 , 서로 영향을 끼치지 않는다.
copy 모듈의 deepcopy() 메서드를 통해 깊은 복사를 실행한다.
예시 보기
import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a) # 깊은 복사
b[0][0] = 777
print(a) # [[1, 2], [3, 4]] → 완전 독립!

할당과 얕은 복사의 차이
할당은 말 그대로 alias 의 의미로 별칭 같은 것이다.
a = b 라고 하면 b를 바라보도록 별칭을 지은것과 같다.
객체로 본다면 같은 객체이며, 속의 내용도 동일하다.
얕은 복사일 경우에는 서로 다른 객체이나, 속의 내용을 공유하고 있다.
객체로 본다면 다른 객체이며, 속의 내용이 동일하다.
깊은 복사를 본다면 오히려 이해가 쉬울 수 있지만, 할당과 얕은 복사의 경우 그 의미가 모호하게 다가 올 수 있다.
코드로 이해하기
a = [[1, 2], [3, 4]]
b = a # 할당 (같은 객체)
c = a[:] # 얕은 복사 (겉은 다르지만 속은 같음)
# 할당의 경우
print(id(a) == id(b)) # ✅ True → 완전히 같은 객체
print(id(a[0]) == id(b[0])) # ✅ True → 내부도 당연히 같음
# 얕은 복사의 경우
print(id(a) == id(c)) # ❌ False → 겉 리스트는 다른 객체
print(id(a[0]) == id(c[0])) # ✅ True → 안쪽 리스트는 같은 객체
is 연산자와
== 연산자
자바를 했었기에 더욱더 헷갈렸던 부분이 아닐 수 없다...
is 연산자는 같은 객체인지 확인하는 용도로 사용하고(identity)
== 연산자는 값이 같은지 확인할 때 쓴다.(equality)
자바에서는 == 연산자를 통해 같은 객체인지 확인하고 equal()을 통해 값을 확인했었는데, == 이 내 생각과 전혀 다른것을 의미한다고 하니 제일 와닿지 않았다.
코드로 이해하기
# int
a = 1000
b = 1000
print(a == b) # ✅ True → 값이 같다
print(a is b) # ❌ False → 다른 객체일 수 있음 (특히 큰 숫자)
#string
x = "hello"
y = "hello"
print(x == y) # ✅ True
print(x is y) # ✅ True (파이썬은 짧은 문자열을 내부적으로 재사용함)
#list
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # ✅ True → 값 같음
print(a is b) # ❌ False → 서로 다른 리스트 객체
c = a
print(c is a) # ✅ True → 같은 객체 (id도 같음)
is 는 정체성을 확인하는데 쓰기 때문에, if a is None : 이런 형식으로 많이 쓰는 것 같다.
익숙해지다보면 익숙해지겠지..
'Developer > Python' 카테고리의 다른 글
python : Iterator, Generator (0) | 2025.03.26 |
---|---|
python : 상속 (inheritance) (0) | 2025.03.25 |
python : 자료형 . 기본 자료형 및 내장 자료형 (0) | 2025.03.20 |
python : 변수 (0) | 2025.03.19 |