class Spam(object):
__slots__ = ('__dict__',)
"일반"클래스보다 작은 인스턴스를 생성합니다. 왜 이런거야?왜 __slots__ = ('__dict__',) 작은 인스턴스를 생성합니까?
출처 : David Beazley's recent tweet.
class Spam(object):
__slots__ = ('__dict__',)
"일반"클래스보다 작은 인스턴스를 생성합니다. 왜 이런거야?왜 __slots__ = ('__dict__',) 작은 인스턴스를 생성합니까?
출처 : David Beazley's recent tweet.
저에게 메모리 절약 효과는 인스턴스에 __weakref__
이없는 것으로 보입니다.
은 우리가 그래서 경우 : (파이썬 3.5.2)에
class Spam1(object):
__slots__ = ('__dict__',)
class Spam2(object):
__slots__ = ('__dict__', '__weakref__')
class Spam3(object):
__slots__ = ('foo',)
class Eggs(object):
pass
objs = Spam1(), Spam2(), Spam3(), Eggs()
for obj in objs:
obj.foo = 'bar'
import sys
for obj in objs:
print(type(obj).__name__, sys.getsizeof(obj))
결과은 다음과 같습니다
Spam1 48
Spam2 56
Spam3 48
Eggs 56
우리는 볼 수는 (a __weakref__
가있다) Eggs
같은 크기 Spam2
(전통적인 수업).
일반적으로 이렇게 절약하면 슬롯이 활성화 된 클래스에서 약한 참조를 사용할 수 없게됩니다. 일반적으로 __slots__
의 절약액은 처음에는 __dict__
을 만들지 않는다는 사실에서 비롯된 것입니다. __dict__
은 다소 희소 한 테이블을 사용하여 구현되므로 (해시 충돌을 방지하고 O (1) 조회/삽입/삭제를 유지하기 위해) 프로그램에서 만드는 각 사전에 사용되지 않는 상당한 공간이 있습니다. 그래도 __slots__
에 '__dict__'
을 추가하면이 최적화를 놓칠 수 있습니다 (사전은 작성됩니다).
class Spam3(object):
__slots__ = ('foo', 'bar')
을, 우리가 걸리는 것을 볼 수 :
는Spam1 48
Spam2 56
Spam3 56
Eggs 56
그래서 각 슬롯은 8 바이트 소요 인스턴스 (나를 위해 - 아마도 8 바이트가 내 시스템에 sizeof(pointer)
이기 때문에). 또한 __slots__
은 설명 자 (인스턴스가 아닌 클래스에 있음)를 작성하여 구현됩니다. 따라서 __slots__
이 dir(instance)
을 통해 나열된 경우에도 실제로는 __slots__
값을 가지고 있지 않습니다.) - 클래스으로 옮겨졌습니다.
이렇게하면 슬롯 사용 가능 클래스가 "기본"값을 설정할 수 없게됩니다. 예 : 다음 코드는 작동하지 않습니다
class Foo(object):
__slots__ = ('foo',)
foo = 'bar'
그래서 그것을 아래로 끓여야 :
는
__slots__ = ('__dict__',)
__dict__
슬롯 및 슬롯 __weakref__
없이__slots__ = ('__dict__',)
__dict__
슬롯이 생성되지만 __weakref__
슬롯은 인스턴스 생성되지 않는다.__slots__
은 실제로 인스턴스 인에 적용되지 않습니다. 클래스에 있습니다 (dir(instance)
에서 볼 수 있음).__slots__
을 사용하면 절약 할 수있는 효과는 미미합니다. 인스턴스에 dict
을 만들지 않으면 (dict
은 데이터 구조에서 다소 희박한 패킹 데이터로 인해 내용에 필요한 저장소의 합계보다 많은 저장소를 차지하므로) __slots__
의 실제 절감액이 발생합니다. 그 중에서도 이러한 방법으로 슬롯을 사용하는 것이 단점이 있습니다 (예 : 인스턴스에 약한 참조 없음).다른 이유로는 부족한 부분이 있기 때문에 다른 곳에서는'__slots__'을 사용합니다. 차이점은'__slots__'과'__weakref__'의 크기 차이와 같아야하지만 그렇지 않습니다! – Kasramvd
@ Kasramvd - 올바르게 이해하면'__slots__'는 _class_에 설명자를 생성하므로'__slots__'는 실제로 _instance_로 옮겨지지 않습니다. 그 인스턴스는 단지 메모리 슬롯 ('sizeof (pointer)')을 가지고 있습니다. 약한 참조와 함께,'getsifof'는'__weakref__'리스트의 크기에 약간의 오버 헤드를 추가합니다. - 추적하기는 꽤 어렵지만 'getsizeof'가 실제로 여러분에게보고하는 숫자를 알려주는 것입니다 :-) – mgilson
네, 분명한 것은 여러분이 언급 한'__weakref__'과'__slots__' 때문에 차이가 있다는 것입니다. 그러나 차이점의 정확한 이유가 무엇인지 알아내는 것은 쉽지 않습니다. 특히 파이썬 수준. – Kasramvd
틀림없이 [__dir__이 (가) 없기 때문에] (https://twitter.com/TeemuRisikko/status/786202646994563077)입니다. 그런 일이 일어나는 이유는 무엇인지 모르겠습니다. –
질문을 예제로 업데이트하는 것이 좋습니다. – Kasramvd
"왜"라는 것이 꽤 명백합니다. "어떻게"라는 것은 파이썬이 객체 별 속성'dict'을 만드는 것을 건너 뜁니다. 속성 이름을'__dict__'라고 명명하는 것은 조금 이상합니다 ...'__init__'에서'self .__ dict__ = {}'를하면'__slots__'의 목적을 무효로합니다. – tdelaney