본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] id() 함수 반환 값의 3가지 숨겨진 의미와 메모리 주소 확인 방법 및 해결책

by Papa Martino V 2026. 2. 27.
728x90

id() 함수
id() 함수

 

파이썬 프로그래밍을 하다 보면 객체의 정체성을 확인하기 위해 id() 함수를 사용하게 됩니다. 하지만 이 숫자가 단순히 "고유 번호"를 넘어 CPython 구현체에서 어떤 물리적 메모리 구조를 반영하는지 깊이 있게 이해하는 개발자는 많지 않습니다. 본 포스팅에서는 id() 값의 본질과 객체 생명 주기와의 상관관계를 심층 분석합니다.


1. id() 함수의 정의와 CPython에서의 특수성

파이썬 공식 문서에 따르면 id() 함수는 객체의 "상대적인 고유 식별자"를 반환합니다. 하지만 우리가 주로 사용하는 CPython 구현체에서 이 값은 객체가 저장된 실제 메모리 주소(Memory Address)를 가리킵니다. 이는 파이썬이 내부적으로 C 언어로 작성되었으며, 객체를 PyObject 구조체 포인터로 관리하기 때문입니다.

중요한 것은 이 값이 객체의 생명 주기 동안에는 변하지 않지만, 객체가 소멸된 후 새로운 객체가 생성되면 동일한 id 값을 재사용할 수 있다는 점입니다. 이를 이해하지 못하면 캐싱이나 객체 비교 시 논리적 오류를 범할 수 있습니다.

2. id() 값과 객체 비교(is vs ==)의 차이점 2가지

개발자들이 가장 흔히 겪는 혼란은 값의 동등성(Equality)과 객체의 정체성(Identity)을 혼동하는 것입니다. 아래 표를 통해 그 차이를 명확히 해결해 보겠습니다.

비교 항목 연산자 비교 대상 (내부 로직) 사용 목적
Identity (정체성) is id(a) == id(b) (메모리 주소 동일 여부) 싱글턴 객체(None 등) 확인 및 동일 메모리 참조 확인
Equality (동등성) == a.__eq__(b) (데이터 내용 동일 여부) 두 객체가 담고 있는 '값'이 같은지 확인

3. CPython의 메모리 관리와 id 재사용 해결 방법

파이썬은 효율적인 메모리 관리를 위해 Reference Counting 방식을 사용합니다. 어떤 객체의 참조 횟수가 0이 되어 가비지 컬렉션(GC) 대상이 되면, 해당 메모리 주소는 비워집니다. 이후 즉시 생성되는 다른 객체가 동일한 메모리 주소를 할당받으면 id() 값이 같게 나오는 현상이 발생합니다. 이러한 "착시 현상"을 피하기 위해서는 객체가 살아있는 동안에만 id() 값을 신뢰해야 하며, 로그 분석 시에는 객체의 생성 시간과 id를 조합하여 고유성을 확보하는 해결 방법을 권장합니다.

4. Sample Example: id() 값의 변화와 메모리 주소 출력

실제 코드를 통해 id() 값이 어떻게 작동하는지, 그리고 16진수 메모리 주소로 변환하는 방법을 살펴보겠습니다.

# 1. 객체 생성 및 id 확인
a = [1, 2, 3]
b = a
c = [1, 2, 3]

print(f"a의 id: {id(a)}")
print(f"b의 id: {id(b)}")
print(f"c의 id: {id(c)}")

# 2. CPython 메모리 주소(16진수) 변환 방법
print(f"a의 메모리 주소: {hex(id(a))}")

# 3. 'is' 연산자와 id 비교
print(f"a is b: {a is b}")  # True (동일 id)
print(f"a is c: {a is c}")  # False (다른 id, 같은 값)

# 4. 재사용 예시 (주의 필요)
del a
del b
d = "New Object"
print(f"d의 id: {id(d)} (이전 a의 id와 같을 수 있음)")

5. 10가지 고급 인사이트: Interning과 id()

파이썬은 성능 향상을 위해 Integer InterningString Interning을 수행합니다. 예를 들어 -5에서 256 사이의 정수는 이미 메모리에 고정된 주소를 가지고 있어, 어디서 선언하든 동일한 id() 값을 반환합니다. 이는 개발자가 메모리 할당 비용을 줄이는 데 큰 역할을 하지만, 큰 숫자나 가변 객체(List, Dict)에서는 적용되지 않는다는 점을 명확히 인지해야 합니다.

6. 결론

id() 함수는 단순히 객체의 이름표가 아니라, CPython 인터프리터가 객체를 관리하는 물리적 지점인 메모리 포인터 그 자체입니다. 이를 활용해 객체 간의 참조 관계를 파악하고, 불필요한 복사를 줄이며, is 연산자를 적재적소에 사용하는 것이 숙련된 파이썬 개발자로 가는 지름길입니다.

내용 출처 및 참고 자료

  • Python 3.12 Official Documentation - Built-in Functions: id()
  • CPython Source Code - Objects/object.c (PyObject definition)
  • "Fluent Python: Clear, Concise, and Effective Programming" by Luciano Ramalho
  • PEP 442 - Safe Object Finalization
728x90