Why does __slots__ = ('__dict__',) produce smaller instances?
<pre><code>class Spam(object):
    __slots__ = ('__dict__',)
</code></pre>

<p>Produces instances smaller than those of a "normal" class. Why is this?</p>

<p>Source: <a href="https://twitter.com/dabeaz/status/785948782219231232" rel="nofollow">David Beazley's recent tweet</a>.  </p>

<p>To me, it looks like the memory savings come from the lack of a <code>__weakref__</code> on the instance.</p>

<p>So if we have:</p>

<pre><code>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))
</code></pre>

<p>The results (on python 3.5.2) are:</p>

<pre><code>Spam1 48
Spam2 56
Spam3 48
Eggs 56
</code></pre>

<p>We see that <code>Spam2</code> (which has a <code>__weakref__</code>) is the same size as <code>Eggs</code> (a traditional class).</p>

<p>Note that normally, this savings is going to be completely insignificant (and prevents you from using weak-references in your slots enabled classes).  Generally, savings from <code>__slots__</code> come from the fact that they don't create a <code>__dict__</code> in the first place.  Since <code>__dict__</code> are implemented using a somewhat sparse table (in order to help avoid hash collisions and maintain O(1) lookup/insert/delete), there's a fair amount of space that isn't used for each dictionary that your program creates.  If you add <code>'__dict__'</code> to your <code>__slots__</code> though, you miss out on this optimization (a dict is still created). </p>

<p>To explore this a little more, we can add more slots:</p>

<pre><code>class Spam3(object):
    __slots__ = ('foo', 'bar')
</code></pre>

<p>Now if we re-run, we see that it takes:</p>

<pre><code>Spam1 48
Spam2 56
Spam3 56
Eggs 56
</code></pre>

<p>So each slot takes 8 bytes on the <em>instance</em> (for me -- likely because 8 bytes is <code>sizeof(pointer)</code> on my system).  Also note that <code>__slots__</code> is implemented by making descriptors (which live on the <em>class</em>, not the instance).  So, the instance (even though you might find <code>__slots__</code> listed via <code>dir(instance)</code>) isn't actually carrying around a <code>__slots__</code> value) -- That's being carried around by the <em>class</em>.</p>

<p>This also has the consequence that your slots enabled class can't set "default" values... e.g. the following code doesn't work:</p>

<pre><code>class Foo(object):
    __slots__ = ('foo',)
    foo = 'bar'
</code></pre>

<p>So to boil it down:</p>

<ul>
<li>each "slot" on an instance takes up the size of a pointer on your system.</li>
<li>without <code>__slots__ = ('__dict__',)</code> a <code>__dict__</code> slot and a <code>__weakref__</code> slot is created on the instance</li>
<li>with <code>__slots__ = ('__dict__',)</code>, a <code>__dict__</code> slot is created but a <code>__weakref__</code> slot is not create on the instance.</li>
<li>In neither case is <code>__slots__</code> actually put on the <em>instance</em>.  It lives on the <em>class</em> (even though you might see it from <code>dir(instance)</code>).</li>
<li>The savings you reap from using <code>__slots__</code> in this way is likely to be insignificant.  Real savings from <code>__slots__</code> happen when you do not create a <code>dict</code> for the instance (since <code>dict</code> take up a more storage than the sum of the storage required for their contents due to somewhat sparse packing data in the data-structure).  On top of that, there are downsides to using slots this way (e.g. no weak-references to your instances).</li>
</ul>

python class python-3.x