How and when to use __slots__ in python

Each python object has a _dict_ attribute which is a dictionary containing
all other attributes. E.g. when you type self.attr python is actually doing
self.dict[‘attr’].

As you can imagine using a dictionary to store attribute takes some extra space
& time for accessing it.

What if you already knew which attributes your class is going to have . Then
using _dict_ to store attributes doesn’t seem to be a good idea as we don’t
need the dynamic nature of dicts .

This is where slots come to rescue .

What are slots in python

_slots_ is a class variable which allows us declare the attributes of a
class explicitly and denying the creation of _dict_ and
_weakref_ for object instances .

The expected attributes can be assigned to _slots_ as a string, iterable,
or sequence of strings with variable names used by instance .

Space saved by not having a _dict_ can be significant . Slots also
improve the attribute lookup speed .

Usage of slots

Python utilises a considerably more compact internal representation for
instances when you define _slots_. Instead of a dictionary, each instance
is created around a small fixed-sized array, similar to a tuple or list.

As a result of using slots, you can no longer add new attributes to
instances
;
you are limited to the attribute names given in the _slots_ specifier.( You
can get around this by adding _dict_ to the _slot_ . The dict will only
initialized when a dynamic attribute is added ) .

Example showing usage of slots :


# A email class with out using slots

class Email :
  def __init__(self,subject,to,message) :
    self.subject = subject
    self.message = message
    self.to = to


class EmailWithSlots :

  __slots__ = ('subject','to','message')

  def __init__(self,subject,to,message) :
    self.subject = subject
    self.message = message
    self.to = to


email = EmailWithSlots('test','me@gmail.com','testing slots')

email.subject
# >> test

email.__dict__  # cant access __dict__ because its not created


# AttributeError                            Traceback (most recent call last)
# <ipython-input-40-b95667a7fb92> in <module>
#  ----> 1 email.__dict__
#
#AttributeError: 'EmailWithSlots' object has no attribute '__dict__'

email.from = "aabid@gmail.com" # cant add an atribute that not in __slots__

# ---------------------------------------------------------------------------
# AttributeError                            Traceback (most recent call last)
# <ipython-input-42-87651e4df821> in <module>
# ----> email.from = "aabid@gmail.com"
#
#AttributeError: 'EmailWithSlots' object has no attribute 'from'



Pros And Cons of slots

Pros

Cons

Inheritance with slots .

Working with slots and Inheritance is a little tricky and need to be taken care
of . Here is How :

   class BaseClass :
       __slots__ = ['x','y','z']


   class Inherited(BaseClass) :
        pass


   Inherited.__slots__

   #>> ['x', 'y', 'z']

   class BaseClass :
       __slots__ = ['x','y','z']


   class Inherited(BaseClass) :
        pass

   class InheritedWithSlots(BaseClass) :
      __slots__ = ()

   Inherited.__slots__
   #>> ['x', 'y', 'z']

   Inherited.__dict__
   #>> {}

   InheritedWithSlots().__dict__
   # AttributeError

Conclusion :

_slots_ allow us to explicitly state which instance variables to expect in
the object

Which gives us following benefits

  1. Faster Attribute Access
  2. Saves Memory

A typical use case

For classes that primarily serve as simple data structures, you can often greatly reduce
the memory footprint of instances by adding the _slots_ attribute to the
class definition.

When slots is a bad idea .

Thanks , for reading till end Happy coding ..

Exit mobile version