Using slots | Python

First, a small disclaimer.

This article is inspired by my learning. When I was just starting my Python-way, on one of the forums I saw a new concept for myself – slots. But no matter how much I searched, there were very few articles on the web on this topic, so it was quite difficult to understand and understand the slots. This article is intended to help beginners in this topic, but I’m sure even experienced developers will find something new here.

When we create objects for classes, memory is required and the attribute is stored as a dictionary (in dict). In case we need to allocate thousands of objects, it will take quite a lot of memory space.

Fortunately, there is a way out – slots, they provide a special mechanism for reducing the size of objects. This is the concept of memory optimization on objects. Also, the use slots allows us to speed up access to attributes.

An example of a python object without slots:

class NoSlots:
  def __init__(self):
    self.a = 1
    self.b = 2 

if __name__ == "__main__": 
  ns = NoSlots()


{'a': 1, 'b': 2}

Because every object in Python contains a dynamic dictionary which allows you to add attributes. For each instance object, we will have a dictionary instance which consumes more space and wastes a lot of RAM. Python does not have a default function to allocate a static amount of memory when creating an object to store all of its attributes.
Usage slots reduces wasted space and speeds up the program by allocating space for a fixed number of attributes.

An example of a python object with slots:

class WithSlots(object):
  slots = ['a', 'b']
  def __init__(self):
    self.a = 1
    self.b = 2

if __name__ == "__main__":
  ws = WithSlots()


['a', 'b']

python example if we use dict:

class WithSlots:
  slots=['a', 'b']
  def init(self):
    self.a = 1
    self.b = 2

if __name__ == "__main__":
  ws = WithSlots()


AttributeError: объект WithSlots не имеет атрибута 'dict'

As we can see, an AttributeError will be raised. It’s not hard to guess that since we can’t call dictthen we will not be able to create new attributes.

This is about the memory consumed, and let’s look at the speed of access to attributes:

Let’s write a little test:

class Foo(object): 
  slots = ('foo',)

class Bar(object): 

def get_set_delete(obj): = 'foo'
def test_foo():  
def test_bar():

And using the module timeit Let’s estimate the execution time:

>>> import timeit
>>> min(timeit.repeat(test_foo))
>>> min(timeit.repeat(test_bar))

So it turns out that a class using slots about 25-30% faster on attribute access operations. Of course, this figure may vary depending on the version of the language or OS on which the program is launched.

As we can see, using slots is quite simple, but there are some pitfalls. For example, inheritance. It must be understood that the meaning slots inherited, however this does not prevent the creation dict.

Thus, child classes will not prohibit adding dynamic attributes, and they will be added to __dict__, with all the ensuing costs (memory and performance).

class SlotsClass:
  slots = ('foo', 'bar')

class ChildSlotsClass(SlotsClass):
>>> obj = ChildSlotsClass()
>>> obj.slots
('foo', 'bar')
>>> = 5
>>> obj.something_new = 3
>>> obj.dict
{'something_new': 3}

If we need the child class to also be limited by slots, we will have to assign a value to the attribute in it as well slots. By the way, there is no need to duplicate the slots already specified in the parent class.

class SlotsClass:
  slots = ('foo', 'bar')

class ChildSlotsClass(SlotsClass):
  slots = ('baz',)
>>> obj = ChildSlotsClass()
>>> = 5py
>>> obj.baz = 6
>>> obj.something_new = 3
Traceback (most recent call last):
File "python", line 12, in <module>
AttributeError: 'ChildSlotsClass' object has no attribute 'something_new'

Much worse is the case with multiple inheritance. If we have two parent classes, each of which has slots defined, then the attempt to create a child class is doomed to failure.

class BaseOne:
  slots = ('param1',)

class BaseTwo:
  slots = ('param2',)
>>> class Child(BaseOne, BaseTwo): slots = ()


Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
class Child(BaseA, BaseB): slots = ()
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict

One way to solve this problem is abstract classes. But I think we’ll talk about it next time.

And finally, the important conclusions:

  • Without dictionary variable dictinstances cannot be assigned attributes not specified in the definition slots. If you try to name a variable that is not in the list, you will get an error AttributeError. If dynamic assignment of new variables is required, add the value 'dict' in attribute declaration slots.

  • Attributes slotsdeclared in parent classes are available in child classes. However, child subclasses will get dictif they don’t override slots.

  • If a class defines a slot also defined in the base class, the instance variable defined by the base class slot is not available. This leads to ambiguous program behavior.

  • Attribute slots does not work for classes inherited from built-in types variable lengthsuch as int, bytes and tuple.

  • Attribute slots any non-string iterable can be assigned. Dictionaries may be used, and the values ​​corresponding to each key may be assigned a special meaning.

  • Purpose class works if both classes have the same slots.

  • Multiple inheritance can be used with multiple slotted parent classes, but only one parent is allowed to have attributes created with slots (other classes must have empty slots mocks), violation will throw an exception TypeError.

I hope everything was simple and clear, and now you will begin to use more often slots in your projects.

I look forward to your opinion on this topic, good luck to everyone!

My GitHub:

Similar Posts

Leave a Reply