이번 포스트에서는 메모리 절약과 필드 생성을 제어 할 수 있는 __slot__에 대해 살펴 보도록 한다.
목차
- 파이썬 클래스 소개
- instance vs static
- >> dict vs slots
- property의 활용
- special method
- callable object
- 클래스 데코레이터(class decorator)
- 상속
- 추상 클래스와 추상 메소드
__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에 대해 알아 보도록 하겠다.