__slots__ 不会(显着)加快属性访问:
>>> class Foo(object):
... __slots__ = ('spam',)
... def __init__(self):
... self.spam = 'eggs'
...
>>> class Bar(object):
... def __init__(self):
... self.spam = 'eggs'
...
>>> import timeit
>>> timeit.timeit('t.spam', 'from __main__ import Foo; t=Foo()')
0.07030296325683594
>>> timeit.timeit('t.spam', 'from __main__ import Bar; t=Bar()')
0.07646608352661133
使用__slots__的目的是节省内存;而不是在实例上使用.__dict__ 映射,该类为__slots__ 中命名的每个属性都具有descriptors objects,并且实例具有分配的属性无论是否它们具有实际值:
>>> class Foo(object):
... __slots__ = ('spam',)
...
>>> dir(Foo())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'spam']
>>> Foo().spam
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: spam
>>> Foo.spam
<member 'spam' of 'Foo' objects>
>>> type(Foo.spam)
<type 'member_descriptor'>
所以python仍然需要查看Foo实例上每个属性访问的类(以找到描述符)。任何未知属性(例如Foo.ham)仍将导致 Python 通过 MRO 类查找该属性,其中包括字典搜索。你仍然可以为 class 分配额外的属性:
>>> Foo.ham = 'eggs'
>>> dir(Foo)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'ham', 'spam']
>>> Foo().ham
'eggs'
插槽描述符在创建类时创建,并访问分配给每个实例的内存以存储和检索对关联值的引用(跟踪实例引用计数的同一块内存和对类对象的引用)。如果没有插槽,则使用 __dict__ 的描述符以相同的方式访问对 dict 对象的引用。