不,PEP 412 可以not make __slots__
多余的。
首先,阿明·里戈(Armin Rigo)是对的,你没有正确衡量它。您需要测量的是物体的大小,加上数值,加上__dict__
本身(对于NoSlots
仅)和钥匙(用于NoSlots
only).
或者你可以按照他的建议去做:
cls = Slots if len(sys.argv) > 1 else NoSlots
def f():
tracemalloc.start()
objs = [cls() for _ in range(100000)]
print(tracemalloc.get_traced_memory())
f()
当我在 OS X 上的 64 位 CPython 3.4 上运行它时,我得到8824968
for Slots
and 25624872
for NoSlots
。所以,它看起来像一个NoSlots
实例占用 88 个字节,而一个Slots
实例占用 256 字节。
这怎么可能?
因为仍然有两点不同__slots__
和一个键分割__dict__
.
首先,字典使用的哈希表保持在 2/3 以下,并且它们呈指数增长并具有最小大小,因此您将有一些额外的空间。通过查看好评的内容,不难算出有多少空间source http://hg.python.org/cpython/file/default/Objects/dictobject.c:您将拥有 8 个哈希桶,而不是 5 个槽指针。
其次,词典本身并不是免费的;它有一个标准对象头、一个计数和两个指针。这听起来可能不是很多,但是当你谈论一个只有几个属性的对象时(请注意most对象只有几个属性……),字典头可以像哈希表一样发挥作用。
当然,在您的示例中,是值,因此这里涉及的唯一成本是对象本身,加上 5 个插槽或 8 个哈希桶和 dict 标头,因此差异非常显着。在真实生活中,__slots__
很少会that有很大的好处。
最后,请注意 PEP 412 仅声明:
基准测试表明,面向对象程序的内存使用量减少了 10% 到 20%
想想你在哪里使用__slots__
。要么节省的金额太大,以至于不使用__slots__
那就太荒谬了,否则你真的需要挤出最后 15%。或者您正在构建一个 ABC 或其他类,您希望将其子类化,而这些子类可能需要节省成本。无论如何,在这些情况下,事实上你获得了一半的好处,而无需__slots__
,甚至三分之二的收益,仍然远远不够;你仍然需要使用__slots__
.
真正的胜利是在不值得使用的情况下__slots__
;您将免费获得一点小福利。
(另外,肯定有一些程序员过度使用了__slots__
,也许这种改变可以说服他们中的一些人将精力投入到微观优化其他不太相关的事情上,如果你幸运的话。)