객체가 메모리에 유지되거나 유지되지 않도록 만드는 것은 참조의 존재 여부로 객체 참조 카운트가 0이 되면 가비지 컬렉터는 해당 객체를 제거하는 것으로 불필요하게 객체를 유지시키지 않으면서 객체를 참조할 수 있으면 도움이 되는 경우가 종종 있는데 대표적인 예로 캐시이다.
약한 참조는 캐시 애플리케이션에서 유용하게 사용되고, 캐시가 참조하고 있다고 해서 캐시된 객체가 계속 남아 있기 원치 않기 때문으로 weakref.ref 객체를 호출해서 참조 대상에 접근하는 방법으로 객체가 살아 있으면 약한 참조 호출은 참조된 객체를 반환하고, 그렇지 않으면 None을 반환한다.
#약한 참조는 콜러블이다. 객체가 살아 있으면 참조된 객체를 반환하고, 그렇지 않으면 None을 반환한다.
import weakref
a_set ={0,1}
wref = weakref.ref(a_set)
wref
wref() #{0,1}
wref() is None
weakref 모듈 문서에선 weakref.ref 클래스는 고급 사용자를 위한 저수준 인터페이스며, 일반 프로그래머는 weakref 컬렉션과 finalize()를 사용하는 것이 좋은 것으로, 직접 만들기보단 내부적으로 약한 참조를 이용하는 finalize()를 사용하는 것이 좋다.
WeakValueDictionary 클래스는 객체에 대한 약한 참조를 값으로 가지는 가변 매핑을 구현하므로 참조된 객체가 프로그램이다.
#Kind 속성과 표준 표현 메서드를 가지고 있는 Cheese 클래스
class Cheese:
def __init__(self,kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
#고객: "파는 치즈가 있긴 하나요?"
import weakref
stock = weakref.WeakValueDictionary()
catalog = [Cheese('Red Leicester'), Cheese('Tilsit'), Cheese('Brie'), Cheese('Parmesan')]
for cheese in catalog:
stock[cheese.kind] = cheese
sorted(stock.keys())
del catalog
sorted(stock.keys())
del cheese
sorted(stock.keys())
WeakKeyDictionary는 애플리케이션의 다른 부분에서 소유하고 있는 객체에 속성을 추가하지 않고 추가적인 데이터를 연결할 수 있다. 이 클래스는 속성 접근을 오버라이드하는 객체에 특히 유용하다.
weakref 모듈은 WeakSet 클래스도 제공하므로 자신의 객체를 모두 알고 있는 클래스를 만들어야 한다면, 각 객체에 대한 참조를 모두 WeakSet 형의 클래스 속성에 저장하는 것이 좋고, 그렇게 하지 않고 일반 집합을 사용할 경우 모든 객체는 가비지 컬렉트되지 않는다.
모든 파이썬 객체가 약한 참조의 대상이 되는 것이 아니므로 기본적인 list와 dict 객체는 참조 대상이 될 수 없다.
class MyList(list):
"""약한 참조의 대상이 될 수 있는 list 서브 클래스"""
a_list = MyList(range(10))
#a_list는 약한 참조의 대상이 될 수 있다
wref_to_a_list = weakref.ref(a_list)
set 객체는 참조 대상이 될 수 있고, 그러므로 set이 사용이 되었다. 사용자 정의형도 아무런 문제없이 참조 대상이 될 수 있기에 바보같은 Cheese 클래스가 필요했지만, int 및 tuple 객체는 클래스를 상속해도 약한 참조의 대상이 될 수 없다.