Blog Entry

Python __slots__

From the Python documentation:

By default, instances of both old and new-style classes have a dictionary for attribute storage. This wastes space for objects having very few instance variables. The space consumption can become acute when creating large numbers of instances. The default can be overridden by defining __slots__ in a new-style class definition. The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.
To test this I created two dummy classes, one with the __slots__ tuple attribute and one without it. Then I compared the instantiation time for the two classes with timeit and did some memory profiling with heapy.
### Code Start ###
import timeit
from guppy import hpy

class Foo(object):
   def __init__(self):
      self.x = 1
      self.y = 2

class FooSlots(object):
   __slots__ = ('x', 'y')
   def __init__(self):
      self.x = 1
      self.y = 2

# test speed...
passes = 1000
print 'Number of instantiations:', passes

t = timeit.Timer('Foo( )', 'from __main__ import Foo')
print 'Foo class instantiation times:', t.timeit(passes)

t = timeit.Timer('FooSlots( )', 'from __main__ import FooSlots')
print 'FooSlots class instantiation times:', t.timeit(passes)

## test memory...
hp = hpy( )
hp.setrelheap( )

class_count = 1000

l = [FooSlots( ) for i in range(class_count)]
h = hp.heap( )
print h

hp.setrelheap( )
l = [Foo( ) for i in range(class_count)]
h = hp.heap( )
print h
### Code End ###
The result of running the tests show that there is not a big difference in instantiation times, but there is a substantial memory saving:
Number of instantiations: 1000
Foo class instantiation times: 0.00138711929321
FooSlots class instantiation times: 0.00114798545837
Partition of a set of 1003 objects. Total size = 32588 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0   1000 100    28000  86     28000  86 __main__.FooSlots
     1      1   0     4128  13     32128  99 list
     2      1   0      448   1     32576 100 types.FrameType
     3      1   0       12   0     32588 100 int
Partition of a set of 2003 objects. Total size = 168540 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0   1000  50   136000  81    136000  81 dict of __main__.Foo
     1   1000  50    28000  17    164000  97 __main__.Foo
     2      1   0     4128   2    168128 100 list
     3      1   0      400   0    168528 100 types.FrameType
     4      1   0       12   0    168540 100 int

Posted on:
2010.01.14 -0600

Tags:
code