본문 바로가기

Python

Python: class __slots__

728x90
반응형

__slots__

 

Python class에서

 

__slots__에 사용할 attributes를 명시하면,

해당 클래스로 생성되는 인스턴스는 __dict__, __weakref__ 를 갖지 않고 생성.

 

기본적으로 python에서 class의 인스턴스는 __dict__에 네임스페이스를 갖는데,

__slots__가 __dict__ 대신 사용될 수 있다.

 

언제? 왜?

 

기본적으로 모든 인스턴스들은 __dict__에 딕셔너리 형태로 네임스페이스를 갖는다.

딕셔너리 형태로 가짐으로써, 인스턴스가 생성된 이후에 인스턴스 attributes들이 생성, 수정, 삭제가 가능하다.

그리고 각각의 인스턴스들이 생성, 수정, 삭제가 가능해야 하고, attirubtes들을 독립적으로 고유하게 가져야 하므로

모든 instance들이 각각의 namespace를 갖는다.

 

그러나 __slots__를 사용하게 되면, 해당 클래스로 생성되는 모든 class는

__slots__에 명시되어 있는 attribute만 가질 수 있게 된다.

 

모든 인스턴스들이 공통된 attributes를 갖게 되기 때문에,

개별 인스턴스들이 굳이 네임스페이스를 가질 필요가 없다.

따라서, instance들이 attribute에 접근할 때는 클래스 attributes로 접근하면 되고,

class에서만 네임스페이스를 가지면 된다.

이로 인해서 인스턴스가 많이 생성되는 상황에서 메모리를 절감할 수 있다.

 

대신, 런타임 중에 attributes가 추가될 수 없으므로 이를 주의해서 사용해야 한다.

하지만 그렇지 않은 상황에서

  - 인스턴스가 많이 생성될 수 있고

  - 인스턴스가 갖는 attribute 또한 많은 상황이라면

__slots__를 통해서 메모리 절감 효과를 효과적으로 얻을 수 있다.

 

 

*유연성 추가: __dict__  with  __slots__

메모리를 절감하면서도 유연성을 갖도록 __slots__와 __dict__를 함께 사용하는 방법도 있다.

이는 고정적으로 사용될 많은 attributes들은 __slots__를 통해서 class 단에서 관리를 하고,

개별 인스턴스들은 __dict__에 새로운 attributes들을 관리할 수 있도록 할 수 있다.

 

class FlexibleSlots:
    __slots__ = ['name', 'identifier', '__dict__', '__weakref__']
    def __init__(self, name, identifier):
        self.name = name
        self.identifier = identifier

fs = FlexibleSlots('flex', 99)
fs.new_attribute = "Now this works"
print(fs.new_attribute)
print(fs.__slots__)
print(fs.__dict__)

# Now this works
# ['name', 'identifier', '__dict__', '__weakref__']
# {'new_attribute': 'Now this works'}

 

위 코드를 보면, __dict__를 __slots__에 명시함으로써 새로운 속성을 추가할 수 있게 되었고,

__slots__에 명시되어 있는 속성들은 __dict__가 아닌 __slots__에서 관리되고 있다.

  - 즉, __slots__에 명시되어 있는 속성들은 개별 인스턴스들이 갖지 않고 class 변수로 가지고 있게 된다.

 

새롭게 추가되는 attributes들은 __dict__에 namespace를 갖게 된다.

 

위와 같은 방식으로, 메모리 절감과 유연성을 함께 가져갈 수 있다.

728x90
반응형