What is the purpose of __slots__?

4

What is this __slots__ property for?

  • in the documentation something about "wasted space", but at the end of the accounts I did not quite understand the purpose of using __slots__ .

    What is it for and when should I use it?

        
  • asked by anonymous 11.01.2017 / 15:54

    1 answer

    8

    __slots__ is a very special attribute for classes - when it is not present, for each new instance of the class, Python creates a new dictionary, but it does not do that if the class sets __slots__ .

    That is, let's suppose I want a "Point" class just to save a couple of coordinates (and I can add methods - but nothing changes here).

    In Python I can write (Python 3 - in Python 2 it is necessary to inherit from object ):

    class Ponto:
        def __init__(self, x=0, y=0):
             self.x = x
             self.y = y
        ...
    

    And this is what we normally know. We can, after instantiating a point, append a z attribute to it:

    p = Ponto()
    p.z = 0
    

    We know that, as a rule, it is not good practice, but the language accepts - and the idea of "consenting adults" from Python is that it avoids bad code that adds random attributes to objects of existing classes.

    Now - most of the time you do not need to add new attributes to your points. And since each instance of Point has a dictionary to store its attributes, it turns out that an instance that would only use a little more than the space required for two objects of type float to - maybe a ~ 80 bytes in total, also from an entire Python dictionary, even though it is zeroed - this is more than 200 bytes long.

    When the class defines __slots__ , Python reserves space for the attributes defined in __slots__ in the class structure, and does not create a new dictionary for each instance.

    That is, this:

    class Ponto:
        __slots__ = ('x', 'y')
        def __init__(self, x=0, y=0):
             self.x = x
             self.y = y
    

    will have the same functionality as the other, but a size of about 80 bytes, not ~ 300.

    On the other hand, trying to create a new attribute results in an error:

      

    AttributeError: 'Point' object has no attribute 'z'

    On large systems that will have thousands of small objects, this can really make a difference. You can also imagine other ways to take advantage of this mechanism - for example: Python automatically creates class attributes ( dir(Ponto) in the above class will show attributes x and y), etc ...

    It is interesting to note that Python builtin classes such as object , int , list , etc ... have __slots__ defined - so you can not create new attributes in such instances - but if you inherit any such type, even if you leave the body of the class blank, you can create new attributes.

    namespace = object()
    namespace.x = 5
    

    (Atribute Error)

    class NS(object): pass
    namespace = NS()
    namespace.x = 5
    

    (ok)

    And it's also important to keep in mind that if you are going to create a class hierarchy and use __slots__ , each subclass will have to set __slots__ as well, otherwise, by default, Python creates __dict__ for class.

        
    11.01.2017 / 17:31