본문 바로가기

진리는어디에/Python

[Python] 클래스(class) #3 __dict__ vs __slots__

이번 포스트에서는 메모리 절약과 필드 생성을 제어 할 수 있는 __slot__에 대해 살펴 보도록 한다.

목차

  1. 파이썬 클래스 소개
  2. instance vs static
  3. >> dict vs slots
  4. property의 활용
  5. special method
  6. callable object
  7. 클래스 데코레이터(class decorator)
  8. 상속
  9. 추상 클래스와 추상 메소드

__dict__

이전 포스트 '클래스(class) #2 instance vs static'에서 우리는 파이썬 클래스의 인스턴스 필드를 생성하면 클래스 객체의 __dict__어트리뷰트에 저장된다는 것을 배웠다.

__dict__에 필드를 저장하게 되면 단점이자 특징이, 외부에서 "새로운 필드(멤버)를 자유롭게 추가" 할 수 있다는 것이다.

예를 들어 클래스 내부에서는 x, y 필드 밖에 만들지 않았지만, 클래스 외부에서 얼마든지 z를 추가 할 수 있다. 이것을 유연성이 좋다고 말할 수도 있지만 반대로 생각하면 필드의 생성에 대한 제약 사항이 없으므로 버그의 원인이 될 수도 있다.

class Foo :
    
    def __init__(self, x, y) :
        self.x = x
        self.y = y

foo = Foo(1, 2)
foo.z = 10  # 클래스 외부에서 새로운 필드 z를 추가 가능

또한, __dict__는 메모리 사용량이 많다. 클래스의 객체를 많이 생성하게 되면 메모리 문제가 발생할 수 있다(하지만 요즘은 메모리가 워낙 넉넉해 객체 만들다 메모리가 부족한 경우는 보기 힘들다).

__slots__

이럴 때 __slots__라는 어트리뷰트를 이용해 필드 생성에 대한 제약과 메모리 절약을 할 수 있다. __slots__는 아래와 같이 스태틱 필드를 만드는것 처럼 클래스 내부에 선언하고, 사용할 필드의 이름을 리스트 형태로 저장한다.

class Bar :
    
    __slots__ = ['x', 'y']
    
    def __init__(self, x, y) :
        self.x = x
        self.y = y

bar = Bar(1, 2) 
bar.z = 10 # AttributeError: 'Bar' object has no attribute 'z'

__slots__를 사용하여 클래스를 정의하면 객체가 생성 되었을 때 __dict__어트리뷰트는 사라지고, x, y 필드는 객체 자체에 데이터가 보관 된다. 그래서 위 예제를 처럼 bar객체에 z를 접근하려 하면 __dict__어트리뷰트가 없으므로 새로운 필드를 생성하지 못하고 z라는 어트리뷰트는 없다는를 오류가 발생 시킨다.

__dict__ vs __slots__

__slot__을 사용했을 때와 그렇지 않았을 때를 비교하기 위해 객체의 어트리뷰트들을 출력하는 dir 표준함수를 통해 객체의 어트리뷰트들을 살펴 보면 아래와 같은 차이가 있다.

  • __slots__를 사용하지 않았을 때
print(dir(foo))

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y', 'z']
  • __slots__를 사용했을 때
print(dir(bar))

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'x', 'y']

"__slots__" 사용 시 객체의 __dict__와 __weakref__ 어트리뷰트가 삭제 된것을 볼 수 있다.

마치며

  • __slots__를 클래스에 정의하면 __slots__에 지정하지 않은 새로운 필드를 추가 할 수 없다.
  • __slots__를 사용하면 메모리 사용량이 약간 줄어든다.

이상으로 파이썬 클래스 정의시 사용되는 __slots__어트리뷰트에 대해 알아 보았다. 다음 포스트에서는 property에 대해 알아 보도록 하겠다.

부록 1. 같이 보면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!