(파이썬) 고정 속성 클래스를 통해 메모리 최적화하기

기본적으로 모든 파이썬의 객체는 내부에 속성의 이름과 값을 담는 사전 객체를 하나씩 포함한다. 이는 __dict__라는 특별한 속성으로 정해져있다. 따라서 파이썬의 객체는 내부의 사전을 이용하여 속성들을 저장할 수 있고, 사전은 변경가능한(mutable) 키-값 쌍이기 때문에 런타임에 객체 인스턴스에 새로운 속성을 추가하는 것이 가능하다.

이러한 동적인 특성은 매우 유연한 프로그램을 작성할 수 있는 장점이 있지만, 모든 객체 인스턴스가 사전 객체를 하나씩 들고 있기 때문에 상당한 메모리 낭비를 수반할 수 있다. 특히 많은 경우에 런타임에 객체 인스턴스에 동적으로 속성을 추가하는 일이 거의 없을 것이다. 오히려 반대로 고정된 몇 개의 속성을 갖는 (따라서 동적으로 속성을 추가/삭제할 일이 없는) 클래스의 인스턴스를 대량으로 생성하는 일은 많을 수 있다. 예를 들어 사진 라이브러리의 수많은 썸네일들을 미리 읽어들여서 관리한다던지, DB로 부터 읽어들인 데이터의 개별 레코드를 대응하는 타입의 클래스 인스턴스로 만드는 경우가 여기에 해당할 수 있다.

고작 수십~수백개의 인스턴스를 동시에 메모리에 적재하는 것은 요즘의 컴퓨터 환경에서는 그다지 무리가 될 일이 아니지만, 수십만~수백만개의 인스턴스를 만들고 관리해야 하는 입장이라면 메모리 사용량이 조금 걱정될 수 있다. 기본적인 파이썬 클래스들의 인스턴스는 유연성을 위해서 적지않은 양의 메모리를 낭비하고 있기 때문에, 이를 개선하는 방법이 있다.

클래스에 __slots__ 속성을 부여하게 되면  __dict__ 속성이 자동으로 주어지지 않는다. 이는  인스턴스가 생성될 때, 미리 정해진 속성을 저장하기 위한 공간이 배정되고, 별도의 사전 객체가 만들어지지 않는다는 뜻이다. __slots__ 속성은 클래스 변수로 아래와 같이 문자열의 연속열로 설정할 수 있다.

다음은 웹페이지에 개제된 이미지들의 정보를 담는 클래스를 고정 속성으로 정의한 예이다.

class HTMLImage:
  __slots__ = ('src', 'dom_id')
  def __init__(self, src, dom_id=""):
    self.src = src
    self.dom_id = dom_id

이렇게 고정 속성을 정의한 클래스에 대해서 런타임에 추가 속성을 지정하려하면 AttributeError 예외가 발생한다. 관련 내용으로 구글링해보면, 다량의 인스턴스를 생성해서 운용하는 경우에 고정 속성 클래스로 만들어 실행한 경우 메모리 스루풋이 50~60%까지 줄어든다는 보고가 있다.