Python : 하위 클래스에서 __slots__ 상속은 실제로 어떻게 작동합니까?
에서 슬롯에 파이썬 데이터 모델의 참조 섹션 사용에 대한주의 사항의 목록이 있습니다 __slots__. 1 번과 6 번 항목이 서로 모순되는 것 같아 완전히 혼란 스럽습니다.
첫 번째 항목 :
- 없는 클래스에서 상속하면 해당 클래스
__slots__의__dict__속성에 항상 액세스 할 수 있으므로__slots__하위 클래스 의 정의는 의미가 없습니다.
여섯 번째 항목 :
__slots__선언 의 동작 은 정의 된 클래스로 제한됩니다. 결과적으로 하위 클래스는__dict__정의하지 않는 한를 갖게됩니다__slots__(추가 슬롯의 이름 만 포함해야 함).
나에게 이러한 항목은 더 나은 단어로 표시되거나 코드를 통해 표시 될 수있는 것 같지만,이 문제에 대해 머리를 감싸려고 노력했지만 여전히 혼란 스럽습니다. 사용 방법을 이해하고 __slots__있으며 작동 방법을 더 잘 이해하려고 노력하고 있습니다.
질문:
누군가가 하위 클래스를 만들 때 슬롯 상속 조건이 무엇인지 평범한 언어로 설명해 주시겠습니까?
(간단한 코드 예제는 도움이되지만 필수는 아닙니다.)
다른 사람들이 언급했듯이 정의하는 유일한 이유 __slots__는 미리 정의 된 속성 집합이있는 간단한 개체가 있고 각 개체가 사전을 가지고 다니기를 원하지 않을 때 일부 메모리를 절약 하는 것 입니다. 이것은 물론 많은 인스턴스를 가질 계획 인 클래스에만 의미가 있습니다.
절감 효과가 즉시 명확하지 않을 수 있습니다. 고려 사항 ... :
>>> class NoSlots(object): pass
...
>>> n = NoSlots()
>>> class WithSlots(object): __slots__ = 'a', 'b', 'c'
...
>>> w = WithSlots()
>>> n.a = n.b = n.c = 23
>>> w.a = w.b = w.c = 23
>>> sys.getsizeof(n)
32
>>> sys.getsizeof(w)
36
이로부터 슬롯이없는 크기가 슬롯이없는 크기 보다 큰 것처럼 보입니다 ! 그러나 이는 sys.getsizeof사전과 같은 "객체 내용"을 고려하지 않기 때문에 실수입니다 .
>>> sys.getsizeof(n.__dict__)
140
딕셔너리만으로 140 바이트를 차지하기 때문에 "32 바이트"객체 n는 각 인스턴스에 관련된 모든 것을 고려하지 않는다고합니다. pympler 와 같은 타사 확장 프로그램으로 더 나은 작업을 수행 할 수 있습니다 .
>>> import pympler.asizeof
>>> pympler.asizeof.asizeof(w)
96
>>> pympler.asizeof.asizeof(n)
288
이것은에 의해 절약 된 메모리 공간을 훨씬 더 명확하게 보여줍니다 __slots__.이 경우와 같은 간단한 객체의 경우, 객체 전체 공간의 거의 2/3 인 200 바이트보다 약간 작습니다. 요즘에는 메가 바이트 정도가 대부분의 응용 프로그램에서 그다지 중요하지 않기 때문에 __slots__한 번에 수천 개의 인스턴스 만 가질 경우에는 그다지 귀찮게 할 가치가 없음을 알 수 있습니다. 그러나 수백만 개의 인스턴스에 대해 매우 중요한 차이를 만듭니다. 또한 미세한 속도 향상을 얻을 수 있습니다 (부분적으로는를 사용하여 작은 개체에 대한 캐시 사용이 향상됨 __slots__).
$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x'
10000000 loops, best of 3: 0.37 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x'
1000000 loops, best of 3: 0.604 usec per loop
$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.28 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.332 usec per loop
그러나 이것은 파이썬 버전에 다소 의존한다 (이 내가 2.5 반복적으로 측정하는 숫자이다; 2.6, 나는에 큰 비교 우위를 참조 __slots__하기위한 설정 속성을하지만 전혀 없음, 실제로 작은 DIS에 대한 장점, 점점 그것을).
이제 상속과 관련하여 인스턴스 가 dict-less가 되려면 상속 체인의 모든 클래스에도 dict-less 인스턴스가 있어야합니다. dict-less 인스턴스가있는 클래스는를 정의하는 클래스와 __slots__대부분의 내장 유형 ( 인스턴스에 dict가있는 내장 유형은 함수와 같은 임의의 속성을 설정할 수있는 인스턴스의 인스턴스입니다)입니다. 슬롯 이름의 겹침은 금지되지 않지만 슬롯이 상속되기 때문에 쓸모없고 일부 메모리를 낭비합니다.
>>> class A(object): __slots__='a'
...
>>> class AB(A): __slots__='b'
...
>>> ab=AB()
>>> ab.a = ab.b = 23
>>>
보시 다시피 인스턴스에 속성 a을 설정할 수 있습니다. 자체적으로 slot을 정의 하지만 에서 슬롯 을 상속합니다 . 상속 된 슬롯을 반복하는 것은 금지되지 않습니다.ABABbaA
>>> class ABRed(A): __slots__='a','b'
...
>>> abr=ABRed()
>>> abr.a = abr.b = 23
그러나 약간의 메모리를 낭비합니다.
>>> pympler.asizeof.asizeof(ab)
88
>>> pympler.asizeof.asizeof(abr)
96
그렇게 할 이유가 없습니다.
class WithSlots(object):
__slots__ = "a_slot"
class NoSlots(object): # This class has __dict__
pass
첫 번째 항목
class A(NoSlots): # even though A has __slots__, it inherits __dict__
__slots__ = "a_slot" # from NoSlots, therefore __slots__ has no effect
여섯 번째 항목
class B(WithSlots): # This class has no __dict__
__slots__ = "some_slot"
class C(WithSlots): # This class has __dict__, because it doesn't
pass # specify __slots__ even though the superclass does.
__slots__가까운 장래 에 사용할 필요가 없을 것입니다 . 약간의 유연성을 희생하면서 메모리를 절약하기위한 것입니다. 개체가 수만 개가 아니면 문제가되지 않습니다.
Python :
__slots__in subclasses의 상속은 실제로 어떻게 작동합니까?1 번과 6 번 항목이 서로 모순되는 것 같아 완전히 혼란 스럽습니다.
Those items don't actually contradict each other. The first regards subclasses of classes that don't implement __slots__, the second regards subclasses of classes that do implement __slots__.
Subclasses of classes that don't implement __slots__
I am increasingly aware that as great as the Python docs are (rightly) reputed to be, they are not perfect, especially regarding the less used features of the language. I would alter the docs as follows:
When inheriting from a class without
__slots__, the__dict__attribute of that class will always be accessible, so a.__slots__definition in the subclass is meaningless
__slots__ is still meaningful for such a class. It documents the expected names of attributes of the class. It also creates slots for those attributes - they will get the faster lookups and use less space. It just allows for other attributes, which will be assigned to the __dict__.
This change has been accepted and is now in the latest documentation.
Here's an example:
class Foo:
"""instances have __dict__"""
class Bar(Foo):
__slots__ = 'foo', 'bar'
Bar not only has the slots it declares, it also has Foo's slots - which include __dict__:
>>> b = Bar()
>>> b.foo = 'foo'
>>> b.quux = 'quux'
>>> vars(b)
{'quux': 'quux'}
>>> b.foo
'foo'
Subclasses of classes that do implement __slots__
The action of a
__slots__declaration is limited to the class where it is defined. As a result, subclasses will have a__dict__unless they also define__slots__(which must only contain names of any additional slots).
Well that's not quite right either. The action of a __slots__ declaration is not entirely limited to the class where it is defined. They can have implications for multiple inheritance, for example.
I would change that to:
For classes in an inheritance tree that defines
__slots__, subclasses will have a__dict__unless they also define__slots__(which must only contain names of any additional slots).
I have actually updated it to read:
The action of a
__slots__declaration is not limited to the class where it is defined.__slots__declared in parents are available in child classes. However, child subclasses will get a__dict__and__weakref__unless they also define__slots__(which should only contain names of any additional slots).
Here's an example:
class Foo:
__slots__ = 'foo'
class Bar(Foo):
"""instances get __dict__ and __weakref__"""
And we see that a subclass of a slotted class gets to use the slots:
>>> b = Bar()
>>> b.foo = 'foo'
>>> b.bar = 'bar'
>>> vars(b)
{'bar': 'bar'}
>>> b.foo
'foo'
(For more on __slots__, see my answer here.)
From the answer you linked:
The proper use of
__slots__is to save space in objects. Instead of having a dynamic dict...
"When inheriting from a class without __slots__, the __dict__ attribute of that class will always be accessible", so adding your own __slots__ cannot prevent objects from having a __dict__, and cannot save space.
The bit about __slots__ not being inherited is a little obtuse. Remember that it's a magic attribute and doesn't behave like other attributes, then re-read that as saying this magic slots behavior isn't inherited. (That's really all there is to it.)
My understanding is as follows:
class
Xhas no__dict__<------->classXand its superclasses all have__slots__specifiedin this case, the actual slots of the class are comprised from the union of
__slots__declarations forXand its superclasses; the behavior is undefined (and will become an error) if this union is not disjoint
'Program Club' 카테고리의 다른 글
| 소스 제어 대 개정 제어? (0) | 2020.12.07 |
|---|---|
| MemoryStream에 쓰기 후 읽기 (0) | 2020.12.07 |
| gcc가 64 비트 플랫폼에서 32 비트 프로그램을 컴파일하도록 강제 (0) | 2020.12.07 |
| 오프라인으로 읽기 위해 Javadoc을 다운로드하는 방법은 무엇입니까? (0) | 2020.12.07 |
| javascript / momentjs에서 날짜를 만들 때 시간대 무시 (0) | 2020.12.07 |