__slots__ =('__ dict__')为什么产生较小的实例?

时间:2016-10-12 15:55:31

标签: python class python-3.x

 //........

 //.........  
 root.setPadding(new Insets(15));
        root.setTop(menuBar);
        //root.setCenter(hbox);

        Scene scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        stage.setTitle("Dummy Title");
        stage.setScene(scene);
        stage.show();

   //........

  //......... 

生成小于“普通”类的实例。这是为什么?

来源:David Beazley's recent tweet

1 个答案:

答案 0 :(得分:8)

对我来说,看起来节省的内存来自实例上缺少__weakref__

所以如果我们有:

class Spam1(object):
    __slots__ = ('__dict__',)

class Spam2(object):
    __slots__ = ('__dict__', '__weakref__')

class Spam3(object):
    __slots__ = ('foo',)

class Eggs(object):
    pass

objs = Spam1(), Spam2(), Spam3(), Eggs()
for obj in objs:
    obj.foo = 'bar'

import sys
for obj in objs:
    print(type(obj).__name__, sys.getsizeof(obj))

结果(在python 3.5.2上)是:

Spam1 48
Spam2 56
Spam3 48
Eggs 56

我们发现Spam2__weakref__)与Eggs(传统类)的大小相同。

请注意,通常情况下,这种节省将是完全无关紧要的(并且阻止您在启用插槽的类中使用弱引用)。通常,__slots__的节省来自于他们首先不创建__dict__这一事实。由于__dict__是使用一个有点稀疏的表实现的(为了帮助避免哈希冲突并维护O(1)查找/插入/删除),因此每个字典都有相当多的空间用于你的程序创建。如果您将'__dict__'添加到__slots__,则会错过此优化(仍然会创建一个dict)。

为了更多地探讨这个问题,我们可以添加更多插槽:

class Spam3(object):
    __slots__ = ('foo', 'bar')

现在,如果我们重新运行,我们会看到它需要:

Spam1 48
Spam2 56
Spam3 56
Eggs 56

因此每个插槽在实例上占用8个字节(对我来说 - 可能因为我的系统上有8个字节sizeof(pointer))。另请注意,__slots__是通过创建描述符(它们位于而非实例)来实现的。因此,实例(即使您可能会发现通过__slots__列出的dir(instance))实际上并未携带__slots__值 - 这是由类< / em>的

这也会导致您的插槽启用类无法设置“默认”值...例如以下代码不起作用:

class Foo(object):
    __slots__ = ('foo',)
    foo = 'bar'

所以要把它煮熟:

  • 实例上的每个“插槽”占用系统上指针的大小。
  • 没有__slots__ = ('__dict__',) __dict__广告位且在实例上创建了__weakref__广告
  • 使用__slots__ = ('__dict__',)创建了__dict__个插槽,但未在该实例上创建__weakref__个插槽。
  • 在任何情况下__slots__实际上都不会放在实例上。它存在于中(即使您可能会从dir(instance)看到它。)
  • 以这种方式使用__slots__所获得的节省可能是微不足道的。如果您没有为实例创建__slots__,则会发生dict的实际节省(因为dict占用的内存多于其内容所需的存储总和,因为包装有些稀疏数据结构中的数据)。最重要的是,以这种方式使用插槽存在缺点(例如,没有对您的实例的弱引用)。