__slots__의 사용방법
Python의 목적은 무엇입니까? 특히 언제 사용하고 싶은지, 언제 사용하지 않는지에 대해서요.
Python의 입니까?
__slots__
그리고 이것을 피해야 할 경우는 무엇입니까?
TLDR:
특수 애트리뷰트를 사용하면 오브젝트인스턴스가 가질 것으로 예상되는 인스턴스 애트리뷰트와 예상되는 결과를 명시적으로 기술할 수 있습니다.
- Atribute 액세스의 고속화.
- 메모리 공간을 절약합니다.
공간 절약은
- 를 " "가에 저장"
__dict__
. - 부모 클래스가 거부되고 사용자가 선언한 경우 거부 및 생성
__slots__
.
빠른 경고
작은 주의사항이지만 상속 트리에서 특정 슬롯을 한 번만 선언해야 합니다.예를 들어 다음과 같습니다.
class Base:
__slots__ = 'foo', 'bar'
class Right(Base):
__slots__ = 'baz',
class Wrong(Base):
__slots__ = 'foo', 'bar', 'baz' # redundant foo and bar
Python은 당신이 이것을 틀렸을 때 반대하지 않는다(아마도 그래야 한다). 그렇지 않으면 문제가 발생하지 않을 수 있지만, 당신의 오브젝트는 그들이 필요로 하는 것보다 더 많은 공간을 차지할 것이다.Python 3.8:
>>> from sys import getsizeof
>>> getsizeof(Right()), getsizeof(Wrong())
(56, 72)
이는 베이스의 슬롯 기술자에 잘못된 슬롯과 다른 슬롯이 있기 때문입니다.일반적으로는 이 문제가 발생하지 않지만 다음과 같은 문제가 발생할 수 있습니다.
>>> w = Wrong()
>>> w.foo = 'foo'
>>> Base.foo.__get__(w)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: foo
>>> Wrong.foo.__get__(w)
'foo'
가장 큰 경고는 다중 상속입니다. "슬롯이 비어 있지 않은 부모 클래스"는 여러 개 조합할 수 없습니다.
이 제한에 대응하려면 , 다음의 베스트 프랙티스에 따라 주세요.한 명 또는 모두를 제외한 모든 부모의 추상화를 배제하고 추상화 빈 슬롯(표준 라이브러리의 추상화 기본 클래스처럼)을 부여합니다.
예에 대해서는 아래의 다중 상속 섹션을 참조하십시오.
요건:
을 「」로 하는 것.
__slots__
__dict__
는 ,로부터 물려받아야 합니다.object
(Python 3 서 2 2 2 Python 2 )「 」의 , 「 」
__dict__
합니다.object
클래스는 "이러한 것은 아니다"라고 선언해야 합니다.__slots__
그 중 도 가질 수 .'__dict__'
작성하다
계속 읽고 싶다면 많은 세부 사항이 있습니다.
「」를 사용하는가?__slots__
속도가 . 속성 접근 고속화.
Python의 제작자인 Guido van Rossum은 그가 실제로 창조했다고 말한다.__slots__
아트리뷰트
현저하게 고속의 액세스를 실증하는 것은 간단한 일입니다.
import timeit
class Foo(object): __slots__ = 'foo',
class Bar(object): pass
slotted = Foo()
not_slotted = Bar()
def get_set_delete_fn(obj):
def get_set_delete():
obj.foo = 'foo'
obj.foo
del obj.foo
return get_set_delete
그리고.
>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085
Ubuntu의 Python 3.5에서는 슬롯 접속이 거의 30% 빨라집니다.
>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342
Windows 의 Python 2 에서는, 약 15% 고속으로 측정했습니다.
「」를 사용하는가?__slots__
: 모리약 : : :
__slots__
각 오브젝트 인스턴스가 차지하는 메모리 공간을 줄이는 것입니다.
이 문서에 대한 저 자신의 기여는 이 배경의 이유를 명확하게 기술하고 있습니다.
「」를 사용해 .
__dict__
중요할 수 있습니다.
SQL Chemy의 특징: 메모리 대폭 절감__slots__
.
하려면 , 로 7 의 하고, 「Ubuntu Linux」의 Python 2.7 의 Anaconda 를 합니다.guppy.hpy
및 (일명 치료법)sys.getsizeof
를 사용하지__slots__
declared 이외는 64바이트입니다.여기에는 다음이 포함되지 않습니다.__dict__
의 게으른 한 번 Python은 Python을 평가해 주셔서 감사합니다.__dict__
참조될 때까지 호출되지 않는 것이 분명하지만 데이터가 없는 클래스는 일반적으로 쓸모가 없습니다. 「」는__dict__
입니다.
''가 있는 __slots__
라고 ()
(데이터 없음)은 16바이트에 불과하며 슬롯에 1개의 아이템이 있는 경우는 56바이트, 2개의 아이템이 있는 경우는 64바이트입니다.
Python의 2.7 , 64비트 Python의 경우 Python 2.7의 3.6의 경우 메모리 소비량을 바이트 단위로 나타냅니다.__slots__
★★★★★★★★★★★★★★★★★」__dict__
(슬롯이 정의되어 있지 않다) 각 포인트에 대해 dict가 3.6으로 증가하는 경우(0, 1, 및2 어트리뷰트를 제외):
Python 2.7 Python 3.6
attrs __slots__ __dict__* __slots__ __dict__* | *(no slots defined)
none 16 56 + 272† 16 56 + 112† | †if __dict__ referenced
one 48 56 + 272 48 56 + 112
two 56 56 + 272 56 56 + 112
six 88 56 + 1040 88 56 + 152
11 128 56 + 1040 128 56 + 240
22 216 56 + 3344 216 56 + 408
43 384 56 + 3344 384 56 + 752
Python Python 3의 딕트는 훌륭한지 알 수 __slots__
이, 「」를 입니다.그것이 바로 당신이 사용하고 싶은 주된 이유입니다.__slots__
.
내 노트의 완성도를 위해 Python 2에서는 64바이트, Python 3에서는 72바이트의 클래스 네임스페이스에 슬롯당 일회성 비용이 있다는 것을 주목하라. 왜냐하면 슬롯은 "members"라고 불리는 속성과 같은 데이터 기술자를 사용하기 때문이다.
>>> Foo.foo
<member 'foo' of 'Foo' objects>
>>> type(Foo.foo)
<class 'member_descriptor'>
>>> getsizeof(Foo.foo)
72
★★★★★★★의 __slots__
:
「」의 __dict__
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , . .object
. 것이 분류된다.object
Python 3 에 pyth 、 Python 2 、 Python 2 、 Python 3 、 Python 2 。
class Base(object):
__slots__ = ()
지금 바로:
>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'
다른 해서 정의해 주세요.__slots__
class Child(Base):
__slots__ = ('a',)
그리고 지금:
c = Child()
c.a = 'a'
단,
>>> c.b = 'b'
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'
__dict__
object를 할 때 sloted objects 서브클래스 할 때, sloted objects를 추가합니다.'__dict__'
__slots__
매겨져 있기 에, 이미 클래스에 ( 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」)
class SlottedWithDict(Child):
__slots__ = ('__dict__', 'b')
swd = SlottedWithDict()
swd.a = 'a'
swd.b = 'b'
swd.c = 'c'
그리고.
>>> swd.__dict__
{'c': 'c'}
선언할 도 없습니다__slots__
하지만, 부모로부터의 하지 않습니다.__dict__
:
class NoSlots(Child): pass
ns = NoSlots()
ns.a = 'a'
ns.b = 'b'
그리고:
>>> ns.__dict__
{'b': 'b'}
★★★★★★★★★★★★★★.__slots__
수 .
class BaseA(object):
__slots__ = ('a',)
class BaseB(object):
__slots__ = ('b',)
양쪽 슬롯이 비어 있지 않은 부모로부터 자녀 클래스를 만드는 데 실패하기 때문에:
>>> class Child(BaseA, BaseB): __slots__ = ()
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
class Child(BaseA, BaseB): __slots__ = ()
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict
이 문제에 직면했을 경우,__slots__
부모로부터, 또는 부모에 대한 제어권을 가지고 있는 경우는, 빈 슬롯을 주거나 추상화를 리팩터 합니다.
from abc import ABC
class AbstractA(ABC):
__slots__ = ()
class BaseA(AbstractA):
__slots__ = ('a',)
class AbstractB(ABC):
__slots__ = ()
class BaseB(AbstractB):
__slots__ = ('b',)
class Child(AbstractA, AbstractB):
__slots__ = ('a', 'b')
c = Child() # no problem!
'__dict__'
로로 합니다.__slots__
「 」 、 「 」 、 「 」:
class Foo(object):
__slots__ = 'bar', 'baz', '__dict__'
그리고 지금:
>>> foo = Foo()
>>> foo.boink = 'boink'
★★★★★★★★★★★★★★★.'__dict__'
슬롯에서는, 동적인 할당이 가능하지만, 예상하는 이름의 슬롯이 있는 것이 장점인 것과 함께, 사이즈의 메리트가 없어집니다.
슬롯되지 않은 객체에서 상속할 경우, 다음과 같은 종류의 의미론을 사용할 수 있습니다.__slots__
()에__slots__
값을 , 값은 "예외"에 수 있습니다.__dict__
.
__slots__
할 수 사실 . 즉, 그냥 을 추가할 수 있습니다.그냥 추가해 주세요."__dict__"
your __slots__
필요한 경우.
로 '어울리지 않다'를 수도 있어요.__weakref__
로로 합니다.__slots__
그 기능이 필요한 경우는, 명시적으로 지정합니다.
명명된 태플을 하위 분류할 때 빈 태플로 설정합니다.
named tuple builtin은 매우 가벼운(기본적으로 tuple의 크기) 불변의 인스턴스를 만들지만, 이점을 얻으려면 이러한 인스턴스를 서브클래스로 분류할 경우 사용자가 직접 수행해야 합니다.
from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
"""MyNT is an immutable and lightweight object"""
__slots__ = ()
사용방법:
>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'
치 않은 「」가 합니다.AttributeError
왜냐하면 우리는 그 창조를 막아왔기 때문이다.__dict__
:
>>> nt.quux = 'quux'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'
허락할 수 있다__dict__
하여 하는 것__slots__ = ()
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .__slots__
서브타입의 태플을 사용합니다.
가장 큰 경고:다중 상속
여러 부모에 대해 비어 있지 않은 슬롯이 동일한 경우에도 함께 사용할 수 없습니다.
class Foo(object):
__slots__ = 'foo', 'bar'
class Bar(object):
__slots__ = 'foo', 'bar' # alas, would work if empty, i.e. ()
>>> class Baz(Foo, Bar): pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict
" " " 를 합니다.__slots__
(추가함으로써) 예방 또는 허용을 선택할 수 있도록 허용함으로써 부모에게 가장 유연한 것을 제공하는 것처럼 보인다.'__dict__'
동적 할당을 얻으려면 위의 섹션을 참조하십시오).
class Foo(object): __slots__ = ()
class Bar(object): __slots__ = ()
class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
b = Baz()
b.foo, b.bar = 'foo', 'bar'
슬롯이 없어도 되므로 슬롯을 추가하고 나중에 삭제하면 문제가 발생하지 않습니다.
위험을 무릅쓰다:인스턴스화를 의도하지 않은 믹스인을 구성하거나 추상 기본 클래스를 사용하는 경우, 비어 있습니다.__slots__
아반 학생들을 위한 유연성의 측면에서 가장 좋은 방법인 것 같습니다.
시연하기 위해 먼저 다중 상속에서 사용할 코드를 가진 클래스를 만듭니다.
class AbstractBase:
__slots__ = ()
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return f'{type(self).__name__}({repr(self.a)}, {repr(self.b)})'
예상되는 슬롯을 상속하여 선언함으로써 위의 내용을 직접 사용할 수 있습니다.
class Foo(AbstractBase):
__slots__ = 'a', 'b'
단, 이것은 단순한 단일 상속이기 때문에 다른 클래스가 필요합니다.아마도 노이즈가 많은 속성을 가진 클래스가 필요할 수도 있습니다.
class AbstractBaseC:
__slots__ = ()
@property
def c(self):
print('getting c!')
return self._c
@c.setter
def c(self, arg):
print('setting c!')
self._c = arg
사실 우리가 줄 수 있었을 텐데.AbstractBase
슬롯 a와 b를 비워두지 않고 다음 선언에서 제외합니다.(미국의
class Concretion(AbstractBase, AbstractBaseC):
__slots__ = 'a b _c'.split()
이제 우리는 양쪽에서 할 수 있게 , '복수 상속'을 거부할 수 .__dict__
★★★★★★★★★★★★★★★★★」__weakref__
★★★★★★★★★★★★★★★★★★:
>>> c = Concretion('a', 'b')
>>> c.c = c
setting c!
>>> c.c
getting c!
Concretion('a', 'b')
>>> c.d = 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Concretion' object has no attribute 'd'
슬롯을 피해야 하는 다른 경우:
- 때 '어울릴 때', ' 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때, 때.
__class__
왜 짓을 (조금만 있으면 됩니다. - long, tuple, str 등의 가변 길이 빌트인을 서브클래스로 분류하고 속성을 추가할 경우 이러한 속성을 사용하지 마십시오.
- 인스턴스 변수의 클래스 속성을 통해 기본값을 제공하려는 경우 이러한 값을 피하십시오.
부분에서도 을 찾을 수 .__slots__
문서(최신 3.7 개발 문서)에 대해 최근 많은 기여를 했습니다.
기타 답변에 대한 비판
현재의 상위 답변들은 구식 정보를 인용하고 있으며 상당히 손사래가 심하고 몇 가지 중요한 면에서 요점을 놓치고 있다.
'은 사용하지 .__slots__
오브젝트를 할 때
견적:
'를 쓰면 것 요.
__slots__
어디서나' '어디서든' '어디서든'
Abstract Class (Abstract Base Class)로부터의 Base Class (Abstract Base Classcollections
.__slots__
그들을 위해 선언되었다.
왜요?
가 " " " 를 거부하는 __dict__
★★★★★★★★★★★★★★★★★」__weakref__
생성, 이러한 것들은 부모 클래스에서 사용할 수 없어야 합니다.
__slots__
는 인터페이스 또는 믹스인을 작성할 때 재사용에 기여합니다.
많은 Python 사용자들이 재사용 가능성을 위해 글을 쓰고 있지 않은 것은 사실이지만, 만약 그렇다면 불필요한 공간 사용을 거부할 수 있는 옵션을 갖는 것이 중요합니다.
__slots__
않다
이 있는 오브젝트를 때, 의 소지가 있는 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」라고 하는 불만에 수 .TypeError
:
>>> pickle.loads(pickle.dumps(f))
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
사실 이건 틀렸어요.이 메시지는 가장 오래된 프로토콜(기본값)에서 온 것입니다.은 최신 프로토콜로 선택할 수 .-1
2.에서는 Python 2.7이 됩니다.2
), 에서는 (2.3'), 3.6'입니다.4
.
>>> pickle.loads(pickle.dumps(f, -1))
<__main__.Foo object at 0x1129C770>
Python 2.7의 경우:
>>> pickle.loads(pickle.dumps(f, 2))
<__main__.Foo object at 0x1129C770>
Python 3.6에서
>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>
그래서 해결된 문제이기 때문에 참고하겠습니다.
인정된 답변(2016년 10월 2일까지)에 대한 비판
첫 번째 단락은 반은 짧고 반은 예측한 것이다.여기 질문에 대한 답이 있습니다.
「 」의
__slots__
객체의 공간을 절약하는 것입니다.오브젝트에 속성을 언제든지 추가할 수 있는 동적 딕트 대신 생성 후 추가를 허용하지 않는 정적 구조가 있습니다.에 의해, 슬롯을 , 1 됩니다.
후반부는 희망사항으로, 빗나갔습니다.
이것은 때때로 유용한 최적화이지만, Python 인터프리터가 충분히 동적이기 때문에 오브젝트에 실제로 추가된 경우에만 dict를 필요로 한다면 완전히 불필요할 것입니다.
하며 Python을 .__dict__
데이터 없이 많은 개체를 만드는 것은 매우 우스꽝스러운 일입니다.
은 너무 를 놓치고 .__slots__
슬롯을 피하는 진짜 이유는 다음과 같습니다(실제로 위의 답변의 나머지 부분을 참조해 주세요).
슬롯이 있는 객체의 동작을 컨트롤 마니아나 고정 타이핑 위니에 의해 악용될 수 있는 방법으로 변경합니다.
파이썬과 그 하기 위한 다른 합니다. 파이썬과 하지 않습니다.__slots__
.
세 번째 단락은 희망사항입니다.모두 합치면, 그 해답자가 작성하지도 않은 엉뚱한 내용들이 대부분이고, 그 사이트에 대한 비판자들을 위한 탄약에 기여하고 있다.
메모리 사용 증거
일반 개체와 슬롯 개체를 만듭니다.
>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()
그 중 100만 개를 인스턴스화합니다.
>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]
「 」로 합니다.guppy.hpy().heap()
:
>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 1000000 49 64000000 64 64000000 64 __main__.Foo
1 169 0 16281480 16 80281480 80 list
2 1000000 49 16000000 16 96281480 97 __main__.Bar
3 12284 1 987472 1 97268952 97 str
...
와 그 오브젝트의 액세스.__dict__
시시시검검검다다
>>> for f in foos:
... f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 1000000 33 280000000 74 280000000 74 dict of __main__.Foo
1 1000000 33 64000000 17 344000000 91 __main__.Foo
2 169 0 16281480 4 360281480 95 list
3 1000000 33 16000000 4 376281480 99 __main__.Bar
4 12284 0 987472 0 377268952 99 str
...
이것은 Python 2.2의 Unifying type과 classs의 Python의 역사와 일치합니다.
로 하면, 「인스턴스」를 하기 위해서, 의 공간이 자동적으로 인스턴스에 는, 「인스턴스」는, 「」에 대응합니다.
__dict__
★★★★★★★★★★★★★★★★★」__weakrefs__
. . . . . . . .__dict__
는사용할때까지초기화되지않기때문에생성하는인스턴스마다빈 딕셔너리가사용하는공간은걱정되지않습니다). '어울릴 수 없어요'라는 문구를 수 요.__slots__ = []
당신의 반에.
「 」의
__slots__
객체의 공간을 절약하는 것입니다.이 사용법 [이 사용법)]__slots__
이것은 때때로 유용한 최적화이지만, Python 인터프리터가 충분히 동적이기 때문에 오브젝트에 실제로 추가된 경우에만 dict를 필요로 한다면 완전히 불필요할 것입니다.안타깝게도 슬롯에 부작용이 있습니다.슬롯이 있는 객체의 동작을 컨트롤 마니아나 고정 타이핑 위니에 의해 악용될 수 있는 방법으로 변경합니다.이것은 좋지 않다. 왜냐하면 제어광들은 메타클래스를 남용하고 정적 타이핑 위니는 장식가를 남용해야 하기 때문이다. 왜냐하면 Python에서는 무언가를 하는 명백한 방법이 하나밖에 없기 때문이다.
CPython 없이도 할 수
__slots__
는 큰 과제이기 때문에 P3k(아직)의 변경 리스트에 포함되지 않았을 가능성이 있습니다.
도 이렇게 하면 것 같아요.__slots__
같은 클래스의 오브젝트를 많이 인스턴스화 할 경우(수천 개, 1천 개). __slots__
메모리 최적화 도구로만 존재합니다.
사용하는 것은 매우 권장되지 않습니다.__slots__
속죄하다
" "를 사용하여 __slots__
는 기본 피클 프로토콜에서는 작동하지 않으므로 이후 버전을 지정해야 합니다.
비단뱀의 다른 자기성찰 기능도 악영향을 받을 수 있습니다.
에는 python이 있습니다.__dict__
: "Attribute: "Attribute"(속성: "속성")를 등 입니다.self.attr
로 Python을 하고 .self.__dict__['attr']
속성을 저장하기 위해 사전을 사용하는 것을 상상할 수 있듯이 접근하기 위해 약간의 추가 공간과 시간이 필요합니다.
을 사용할 는 을 사용합니다.__slots__
그에 대해 「」, 「」, 「」는 없습니다.__dict__
에 대한 포인터를통해 직접 .아트리뷰트
C C 스타일 구조를 사용할 수 .__slots__
오브젝트 크기를 압축하여 속성 접근 시간을 단축합니다.포인트입니다.것 '점수'를 .__slots__
츠키노
, '보다 낫다'를 하는 방법이 있습니다.__slots__
:
>>> class Test(object): #Must be new-style class!
... __slots__ = ['x', 'y']
...
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']
때문에, 「」를 실장하려면 , 「」__slots__
추가 행만 있으면 됩니다(클래스를 새로운 스타일의 클래스로 만들 수 있습니다).이렇게 하면 필요에 따라 커스텀 피클 코드를 작성할 필요가 있어 이러한 클래스의 메모리 용량을 5배로 줄일 수 있습니다.
슬롯은 함수 호출 시 "이름 있는 메서드 디스패치"를 제거하기 위해 라이브러리 호출에 매우 유용합니다.이는 SWIG 매뉴얼에 기재되어 있습니다.일반적으로 슬롯을 사용하여 함수의 오버헤드를 줄이고 싶은 고성능 라이브러리의 경우 훨씬 더 빠릅니다.
이것은 OPs 질문과는 직접 관련이 없을 수 있습니다.오브젝트상의 슬롯 구문을 사용하는 것보다 확장기능의 구축과 관련이 있습니다.그러나 슬롯의 사용과 그 배경에 있는 몇 가지 이유를 설명하는 데 도움이 됩니다.
클래스 인스턴스의 Atribute에는 인스턴스, Atribute 이름 및 Atribute 값의 3가지 속성이 있습니다.
일반 속성 액세스에서는 인스턴스가 사전으로 기능하고 속성의 이름이 해당 사전 검색 값에서 키로 기능합니다.
instance(필수) --> 값
__slots__ 액세스에서는 Atribute 이름이 딕셔너리로 기능하고 인스턴스가 딕셔너리 검색 값에서 키로 기능합니다.
attribute(필수) --> 값
Flyweight 패턴에서는 Atribute의 이름이 딕셔너리로 기능하고 값이 해당 딕셔너리에서 인스턴스를 검색하는 키로 기능합니다.
attribute(값) --> 인스턴스
「 」의 예.__slot__
여하하다
★★★★★★★★★★★★★★★★★★ 없음.__slots__
가 없으면__slot__
클래스 속성에서 새 속성을 객체에 추가할 수 있습니다.
class Test:
pass
obj1=Test()
obj2=Test()
print(obj1.__dict__) #--> {}
obj1.x=12
print(obj1.__dict__) # --> {'x': 12}
obj1.y=20
print(obj1.__dict__) # --> {'x': 12, 'y': 20}
obj2.x=99
print(obj2.__dict__) # --> {'x': 99}
위의 예를 보면, obj1과 obj2는 그들만의 x와 y 속성을 가지고 있으며 python도 생성되어 있는 것을 알 수 있습니다.dict
각 오브젝트(obj1 및 obj2)의 어트리뷰트.
내 클래스 테스트에 수천 개의 개체가 있다고 가정해 보십시오.추가 속성 생성dict
각 오브젝트에 대해서, 코드에 대량의 오버헤드(메모리, 컴퓨팅 파워 등)가 발생합니다.
★★★★★★★★ 포함__slots__
다음 예제에서는 내 클래스 테스트에 다음 항목이 포함되어 있습니다.__slots__
이제 새로운 할 수 속성 제외).x
비단뱀을 dict
아트리뷰트이렇게 하면 각 개체에 대한 오버헤드가 제거되므로 개체가 많을 경우 이러한 오버헤드가 커질 수 있습니다.
class Test:
__slots__=("x")
obj1=Test()
obj2=Test()
obj1.x=12
print(obj1.x) # --> 12
obj2.x=99
print(obj2.x) # --> 99
obj1.y=28
print(obj1.y) # --> AttributeError: 'Test' object has no attribute 'y'
다른 답변과 더불어__slots__
또한 Atribut을 사전 정의된 목록으로 제한하여 인쇄상의 보안을 약간 강화합니다.자바스크립트JavaScript에서는 의도 여부에 관계없이 기존 오브젝트에 새로운 속성을 추가할 수 있습니다.
다음은 아무것도 하지 않지만 속성을 추가할 수 있는 일반적인 비슬롯 개체를 보여 줍니다.
class Unslotted:
pass
test = Unslotted()
test.name = 'Fred'
test.Name = 'Wilma'
Python은 대소문자를 구분하기 때문에 철자는 같지만 대소문자가 다른 두 속성이 다릅니다.만약 그 중 하나가 오타라고 의심된다면, 그것은 불운이다.
슬롯을 사용하면, 다음을 제한할 수 있습니다.
class Slotted:
__slots__ = ('name')
pass
test = Slotted()
test.name = 'Fred' # OK
test.Name = 'Wilma' # Error
두 아트리뷰트 「」 「」 「」)입니다.Name
는) 때문에 .__slots__
★★★★★★ 。
이 제품을 사용하는 것이 좋을 것 같습니다.__slots__
가능한 경우 오브젝트를 더 잘 제어할 수 있습니다.
.9 , Python 3.9부터는dict
는, 할 수 .__slots__
None
는 설명 없이 Atribute에 사용할 수 있으며 설명을 제공해도 개인 변수는 표시되지 않습니다.
class Person:
__slots__ = {
"birthday":
"A datetime.date object representing the person's birthday.",
"name":
"The first and last name.",
"public_variable":
None,
"_private_variable":
"Description",
}
help(Person)
"""
Help on class Person in module __main__:
class Person(builtins.object)
| Data descriptors defined here:
|
| birthday
| A datetime.date object representing the person's birthday.
|
| name
| The first and last name.
|
| public_variable
"""
다른 __slots__
는 ProxyTypes 패키지에서 오브젝트프록시에 속성을 추가하는 것입니다.PEACK 을 사용합니다.ObjectWrapper
를 사용하면 다른 오브젝트를 프록시 할 수 있지만 프록시 오브젝트와의 모든 상호작용을 대행 수신할 수 있습니다.것은 ), 세이프 에 대한 블로킹래퍼를 3).스하는 토네이도에 기반한 비동기 구현 주위에 스레드 세이프 차단 래퍼를 구현하기 위해 사용하였습니다.concurrent.Future
츠요시
기본적으로 프록시 개체에 대한 모든 속성 액세스는 프록시 개체에서 결과를 제공합니다.가 있는 는, 「」를 참조해 주세요.__slots__
사용할 수 있습니다.
from peak.util.proxies import ObjectWrapper
class Original(object):
def __init__(self):
self.name = 'The Original'
class ProxyOriginal(ObjectWrapper):
__slots__ = ['proxy_name']
def __init__(self, subject, proxy_name):
# proxy_info attributed added directly to the
# Original instance, not the ProxyOriginal instance
self.proxy_info = 'You are proxied by {}'.format(proxy_name)
# proxy_name added to ProxyOriginal instance, since it is
# defined in __slots__
self.proxy_name = proxy_name
super(ProxyOriginal, self).__init__(subject)
if __name__ == "__main__":
original = Original()
proxy = ProxyOriginal(original, 'Proxy Overlord')
# Both statements print "The Original"
print "original.name: ", original.name
print "proxy.name: ", proxy.name
# Both statements below print
# "You are proxied by Proxy Overlord", since the ProxyOriginal
# __init__ sets it to the original object
print "original.proxy_info: ", original.proxy_info
print "proxy.proxy_info: ", proxy.proxy_info
# prints "Proxy Overlord"
print "proxy.proxy_name: ", proxy.proxy_name
# Raises AttributeError since proxy_name is only set on
# the proxy object
print "original.proxy_name: ", proxy.proxy_name
원래 질문은 메모리뿐만 아니라 일반적인 사용 사례에 대한 것이었습니다.따라서 대량의 오브젝트를 인스턴스화할 때(예: 큰 문서를 오브젝트로 해석하거나 데이터베이스에서 해석할 때)에도 퍼포먼스가 향상된다는 점에 유의해야 합니다.
슬롯과 슬롯을 사용하지 않고 100만 개의 엔트리를 가진 객체트리를 작성하는 방법을 비교합니다.또한 트리에 플레인 딕트를 사용할 때의 퍼포먼스(OSX의 경우 Py2.7.10):
********** RUN 1 **********
1.96036410332 <class 'css_tree_select.element.Element'>
3.02922606468 <class 'css_tree_select.element.ElementNoSlots'>
2.90828204155 dict
********** RUN 2 **********
1.77050495148 <class 'css_tree_select.element.Element'>
3.10655999184 <class 'css_tree_select.element.ElementNoSlots'>
2.84120798111 dict
********** RUN 3 **********
1.84069895744 <class 'css_tree_select.element.Element'>
3.21540498734 <class 'css_tree_select.element.ElementNoSlots'>
2.59615707397 dict
********** RUN 4 **********
1.75041103363 <class 'css_tree_select.element.Element'>
3.17366290092 <class 'css_tree_select.element.ElementNoSlots'>
2.70941114426 dict
테스트 클래스(ID, 슬롯에서 추가):
class Element(object):
__slots__ = ['_typ', 'id', 'parent', 'childs']
def __init__(self, typ, id, parent=None):
self._typ = typ
self.id = id
self.childs = []
if parent:
self.parent = parent
parent.childs.append(self)
class ElementNoSlots(object): (same, w/o slots)
테스트 코드, 상세 모드:
na, nb, nc = 100, 100, 100
for i in (1, 2, 3, 4):
print '*' * 10, 'RUN', i, '*' * 10
# tree with slot and no slot:
for cls in Element, ElementNoSlots:
t1 = time.time()
root = cls('root', 'root')
for i in xrange(na):
ela = cls(typ='a', id=i, parent=root)
for j in xrange(nb):
elb = cls(typ='b', id=(i, j), parent=ela)
for k in xrange(nc):
elc = cls(typ='c', id=(i, j, k), parent=elb)
to = time.time() - t1
print to, cls
del root
# ref: tree with dicts only:
t1 = time.time()
__slots__의 사용방법 droot = {'childs': []}
for i in xrange(na):
ela = {'typ': 'a', id: i, 'childs': []}
droot['childs'].append(ela)
for j in xrange(nb):
elb = {'typ': 'b', id: (i, j), 'childs': []}
ela['childs'].append(elb)
for k in xrange(nc):
elc = {'typ': 'c', id: (i, j, k), 'childs': []}
elb['childs'].append(elc)
td = time.time() - t1
print td, 'dict'
del droot
는 기본적으로는__slots__
도 모른다고 __slots__
실제로 Lightweight 또는 Flyweight 설계 패턴을 사용하려고 합니다.Python 객체만을 더 이상 사용하지 않는 경우입니다.대신 배열, 구조 또는 numpy 배열 주위에 Python 개체와 같은 래퍼를 사용해야 합니다.
class Flyweight(object):
def get(self, theData, index):
return theData[index]
def set(self, theData, index, value):
theData[index]= value
클래스 유사 래퍼에는 속성이 없으며 기본 데이터에 대해 작동하는 메서드만 제공됩니다.메서드는 클래스 메서드로 축소할 수 있습니다.실제로, 기본 데이터 배열에서 작동하는 기능만으로 축소할 수 있습니다.
언급URL : https://stackoverflow.com/questions/472000/usage-of-slots
'programing' 카테고리의 다른 글
easy_install보다 pip을 사용하는 이유는 무엇입니까? (0) | 2023.01.25 |
---|---|
Python에서는 메서드를 덮어쓰고 있다는 것을 어떻게 표시합니까? (0) | 2023.01.25 |
인덱스된 키에 가입하더라도 MySQL(InnoDB) 쿼리가 느립니다. 이유는 무엇입니까? (0) | 2023.01.25 |
오류: (23, 17) 해결 실패: junit: junit: 4.12 (0) | 2023.01.25 |
빈 어레이를 생성하여 NumPy에 추가하는 방법은 무엇입니까? (0) | 2023.01.25 |