我听说__slots__
通过避免字典查找使对象更快。我的困惑来自 Python 是一种动态语言。在静态语言中,我们a.test
通过编译时优化来避免字典查找,以将索引保存在我们运行的指令中。
现在,在 Python 中,a
可以很容易地成为具有字典或不同属性集的另一个对象。似乎我们仍然需要进行字典查找 - 唯一的区别似乎是我们只需要一个类的字典,而不是每个对象的字典。
有了这个理性,
- 如何
__slots__
避免字典查找? - 插槽是否使访问对象更快?
我听说__slots__
通过避免字典查找使对象更快。我的困惑来自 Python 是一种动态语言。在静态语言中,我们a.test
通过编译时优化来避免字典查找,以将索引保存在我们运行的指令中。
现在,在 Python 中,a
可以很容易地成为具有字典或不同属性集的另一个对象。似乎我们仍然需要进行字典查找 - 唯一的区别似乎是我们只需要一个类的字典,而不是每个对象的字典。
有了这个理性,
__slots__
避免字典查找?__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__
,并且实例具有分配的属性,无论它们是否具有实际值:
>>> 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 搜索该属性,其中包括字典搜索。您仍然可以为该类分配其他属性:
>>> 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'
The slot descriptors are created when the class is created, and access memory assigned to each instance to store and retrieve a reference to the associated value (the same chunk of memory that tracks instance reference counts and a reference back to the class object). Without slots, a descriptor for __dict__
is used accessing a reference to a dict
object in the same manner.
它可能会加速您实例化同一类的许多对象的程序,真正永远不会更改它们具有的属性,并且所有这些重复字典上的缓存未命中会带来真正的性能问题。
这实际上只是一般情况下的一个特例,在这种情况下,节省空间有时也可以节省时间,而缓存是限制因素。
因此,它可能不会使访问一个对象更快,但可能会加快访问许多相同类型的对象。
另请参阅此问题。