본문으로 이동

Python

Python에서는 이름이 객체를 가리킨다. 객체의 값과 그 객체에 연결된 이름을 구분하면, 함수 호출 뒤 어떤 변경이 남는지와 객체가 언제 회수될 수 있는지를 함께 이해할 수 있다.

이름, 값과 객체의 동일성

b = a는 보통 객체를 복제하는 표현이 아니다. 두 이름이 같은 객체를 가리킨다. b에 다른 값을 대입하면 바뀌는 것은 그 이름의 연결이다. is는 같은 객체인지 비교하고 id()는 동일성을 나타내는 정수를 돌려준다. CPython에서는 주소를 사용하지만 이를 모든 Python 구현의 물리 주소라고 가정하지 않는다. 객체가 사라진 뒤 같은 ID가 다시 쓰일 수도 있다.

숫자·문자열·Tuple은 Immutable이고 List·Dict·Set은 Mutable이다. Tuple 안에 List가 들어 있으면 그 List의 내용은 바뀔 수 있다. Tuple이 고정하는 것은 담긴 객체들의 연결이며, 안의 객체까지 모두 불변으로 만드는 것은 아니다. 사용자 정의 객체의 변경 가능성은 그 타입의 설계에 따라 살펴야 한다. Python 객체의 동일성과 변경 가능성

이 구분을 함수 호출에 적용한 예제는 함수에서, 새 Container를 만드는 복사의 범위는 기본 문법의 복사에서 다룬다.

CPython에서 참조와 순환을 살펴본다

CPython은 참조 수 관리에 순환 참조 탐지를 더한다. gc.disable()은 자동 순환 수집을 멈추는 기능이며 참조 수 관리를 끄는 것은 아니다. gc.collect()는 명시적으로 수집을 요청한다. 반환하는 전체 객체 수가 방금 만든 객체 수와 정확히 같으리라고 가정하지 않는다. gc 인터페이스

다음 예제는 별칭을 추가·삭제할 때의 참조 수 변화와 바깥에서 끊어진 순환을 비교한다. 자동 순환 수집을 잠깐 멈추고 명시적 수집을 요청하며, 마지막에는 원래 설정을 복구한다. Weak Reference는 관찰할 객체를 살아 있게 붙잡지 않는다.

Python · 실행 미지원
import gc
import sys
import weakref


class Node:
    def __init__(self):
        self.ref = None


item = Node()
before = sys.getrefcount(item)
alias = item
added = sys.getrefcount(item) - before
del alias
restored = sys.getrefcount(item) == before
assert added == 1 and restored
print("reference added:", added, "restored:", restored)
del item

was_enabled = gc.isenabled()
gc.disable()
try:
    a, b = Node(), Node()
    a.ref, b.ref = b, a
    watch_a, watch_b = weakref.ref(a), weakref.ref(b)
    del a, b
    retained = watch_a() is not None and watch_b() is not None
    assert retained
    gc.collect()
    cleared = watch_a() is None and watch_b() is None
    assert cleared
    print("cycle before collection:", retained)
    print("cycle after collection cleared:", cleared)
finally:
    if was_enabled:
        gc.enable()

CPython 3.13.13에서 위 변화와 순환 회수를 확인했다. sys.getrefcount() 자체의 임시 참조와 Immortal 객체 등 구현상의 조건 때문에 임의 객체의 출력값을 정확한 소유자 수로 해석하지 않는다. 예제는 새로 만든 보통 객체의 변화를 비교한다. getrefcount의 한계

수집 세대와 임계값도 버전·빌드의 설정이다. 현재 값은 gc.get_threshold()로 확인하고 해당 버전의 문서와 함께 읽는다. 정해진 할당 횟수가 곧 동일한 실행 시점이나 정지 시간을 뜻하지는 않는다. Python 언어 전체가 참조가 사라진 즉시 객체를 회수한다고 보장하지 않으므로, 파일 등은 Context Manager와 명시적인 종료로 관리한다.