본문 바로가기
Engineering WIKI/Python

파이썬 __ slots __

by wonos 2022. 4. 28.

파이썬 __ slots __

클래스를 사용해보았다면 __dict__을 통해서 클래스의 인스턴스가 가진 모든 속성을 확인해본적이 있을 것이다. 딕셔너리는 메모리를 많이 잡아먹는 단점이 있는데, 만약 수 백만개의 인스턴스를 생성한다면 그 만큼 사용되는 메모리가 매우 크게 증가한다는 것을 의미한다. 클래스가 가지는 속성을 제한함으로써 최적화를 할 수 있으며 이 때 필요한 __slot__이라는 키워드에 대해서 정리해보자.

slots 이란?

slots은 클래스가 가진 속성을 제한할때 사용한다. 클래스의 dict 속성을 최적화하는 데에 사용할 수 있는데 기존의 딕셔너리로 관리하는 속성을 집합 형태의 Set으로 바꿈으로써 동작한다. 메모리를 절약할 수 있다는 장점이 있다.

( __slots__은 객체마다 생성되는 __dict__을 생성못하게 하여 메모리 효율성을 높이고, 객체의 속성(변수) 추가(생성)을 제한할 수 있다. )

코드로 살펴보는 slots

slots를 사용하는 클래스와 그렇지 않은 클래스를 정의하고 인스턴스까지 생성한 뒤 각 인스턴스의 네임 스페이스를 살펴보자.

class SlotClass:
	__slots__ = ('name', )

class NoSlotClass:
	pass

slot = SlotClass()
no_slot = NoSlotClass()
no_slot.name = 'a'

slot.__dict__  # 에러 - slots은 dict을 가지고 있지 않기 때문에
no_slot.__dict__

slot 인스턴스는 slots을 사용하고있기 때문에 더 이상 네임 스페이스를 __dict__을 통해서 관리하지 않는다. 메모리 사용량에 있어서 얼마나 차이가 있는지 실험을 해보자.

class Point3D:
    __slots__ = ('x', 'y', 'z')  # 속성(변수)를 x, y, z로 제한함
    
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return '3D 좌표 : ({0}, {1}, {2})'.format(self.x, self.y, self.z)

def main():
    p1 = Point3D(1, 1, 1)
    p2 = Point3D(24, 27, 31)
    print(p1)  # 3D 좌표 : (1, 1, 1)
    print(p2)  # # 3D 좌표 : (24, 27, 31)
    
    #p1.v1 = 30
    # AttributeError: 'Point3D' object has no attribute 'v1'
    
    #print(p1.__dict__)
    # AttributeError: 'Point3D' object has no attribute '__dict__'
    
 
main()
  • 클래스 내에 slots 가 없으면
  • p1.v1 = 30 이 실행되어
  • print(p1.dict)의 결과, {'x': 1, 'y': 1, 'z': 1, 'v1': 30} 출력됨

slots 사용 여부에 따른 메모리 사용량 비교

import timeit

def check_time(obj):
	def inner():
		obj.name = 'hello'
		del obj.name
	return inner

min(timeit.repeat(check_time(slot), number=10000000))# 1.6706519379999918
min(timeit.repeat(check_time(no_slot), number=10000000))# 2.139917491999995

timeit 모듈의 repeat 함수를 이용했다. 인스턴스의 name 속성에 hello라는 문자열을 저장하는 작업을 천만번 수행하도록 했고 그 중에서 가장 짧은 시간이 출력되도록 했다. 결과는 큰 차이가 발생하진 않았지만 slots를 사용하지 않았을때 시간이 더 걸리는 것으로 보아 작업량이 더 많아 메모리를 더 점유한다고 생각할 수 있겠다.

정리

파이썬 클래스가 가지는 딕셔너리 형태의 속성은 런타임에도 임의의 새로운 속성을 추가할 수 있다는 유연성을 제공해주지만 더 많은 메모리를 사용한다는 단점도 가지고 있다. 클래스 속성을 딕셔너리로 관리하는 대신에 slots을 사용하여 고정된 속성 집합을 사용하게 함으로써 메모리 사용량을 줄이고 최적화 할 수 있다.

정말 많은 객체를 생성할 거라고 예상되는 클래스는 slots으로 속성을 관리하는 것을 추천한다!!