Rectangle 27 1

python Usage of __slots__?


Can you elaborate? Do you mean: (a) it doesn't actually break pickle, (b) it breaks pickle, but that's easy to fix, (c) you shouldn't be using pickle anyways, or (d) something else? :)

I see your point, but slots offer faster attribute access as well (as others have stated). In that case you don't need "to instantiate a lot (hundreds, thousands) of objects of the same class" in order to gain performance. What you need instead are a lot of accesses to the same (slotted) attribute of the same instance. (Please correct me if I'm wrong.)

It's highly discouraged to use __slots__ for constraining attribute creation, and in general you want to avoid it because it breaks pickle, along with some other introspection features of python.

You would want to use __slots__ if you are going to instantiate a lot (hundreds, thousands) of objects of the same class. __slots__ only exists as a memory optimization tool.

Note
Rectangle 27 1

python Usage of __slots__?


@Merlyn Morgan-Graham, it serves as a hint on which to pick: regular access, __slots__, or flyweight.

An attribute of a class instance has 3 properties: the instance, the name of the attribute, and the value of the attribute.

In __slots__ access, the name of the attribute acts as the dictionary and the instance acts as the key in the dictionary looking up value.

In flyweight pattern, the name of the attribute acts as the dictionary and the value acts as the key in that dictionary looking up the instance.

In regular attribute access, the instance acts as a dictionary and the name of the attribute acts as the key in that dictionary looking up value.

This is a good share, and won't fit well in a comment on one of the answers that also suggest flyweights, but it is not a complete answer to the question itself. In particular (in just context of the question): why Flyweight, and "what are the cases one should avoid ..." __slots__?

Note
Rectangle 27 1

python Usage of __slots__?


from peak.util.proxies import ObjectWrapper

class Original(object):
    def __init__(self):
        self.name = 'The Original'

class ProxyOriginal(ObjectWrapper):

    __slots__ = ['proxy_name']

    def __init__(self, subject, proxy_name):
        # proxy_info attributed added directly to the
        # Original instance, not the ProxyOriginal instance
        self.proxy_info = 'You are proxied by {}'.format(proxy_name)

        # proxy_name added to ProxyOriginal instance, since it is
        # defined in __slots__
        self.proxy_name = proxy_name

        super(ProxyOriginal, self).__init__(subject)

if __name__ == "__main__":
    original = Original()
    proxy = ProxyOriginal(original, 'Proxy Overlord')

    # Both statements print "The Original"
    print "original.name: ", original.name
    print "proxy.name: ", proxy.name

    # Both statements below print 
    # "You are proxied by Proxy Overlord", since the ProxyOriginal
    # __init__ sets it to the original object 
    print "original.proxy_info: ", original.proxy_info
    print "proxy.proxy_info: ", proxy.proxy_info

    # prints "Proxy Overlord"
    print "proxy.proxy_name: ", proxy.proxy_name
    # Raises AttributeError since proxy_name is only set on 
    # the proxy object
    print "original.proxy_name: ", proxy.proxy_name

Another somewhat obscure use of __slots__ is to add attributes to an object proxy from the ProxyTypes package, formerly part of the PEAK project. Its ObjectWrapper allows you to proxy another object, but intercept all interactions with the proxied object. It is not very commonly used (and no Python 3 support), but we have used it to implement a thread-safe blocking wrapper around an async implementation based on tornado that bounces all access to the proxied object through the ioloop, using thread-safe concurrent.Future objects to synchronise and return results.

By default any attribute access to the proxy object will give you the result from the proxied object. If you need to add an attribute on the proxy object, __slots__ can be used.

Note
Rectangle 27 1

python Usage of __slots__?


Python 2.7             Python 3.6
attrs  __slots__  __dict__*   __slots__  __dict__* | *(no slots defined)
none   16         56 + 272   16         56 + 112 | if __dict__ referenced
one    48         56 + 272    48         56 + 112
two    56         56 + 272    56         56 + 112
six    88         56 + 1040   88         56 + 152
11     128        56 + 1040   128        56 + 240
22     216        56 + 3344   216        56 + 408     
43     384        56 + 3344   384        56 + 752
'__dict__'
>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342
>>> Foo.foo
<member 'foo' of 'Foo' objects>
>>> getsizeof(Foo.foo)
72
>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'
>>> c = Concretion('a', 'b')
>>> c.c = c
setting c!
>>> c.c
getting c!
Concretion('a', 'b')
>>> c.d = 'd'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Concretion' object has no attribute 'd'
>>> c.b = 'b'
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'
>>> class Child(BaseA, BaseB): __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
>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()
>>> foo = Foo()
>>> foo.boink = 'boink'
>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]
>>> for f in foos:
...     f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
 Index  Count   %      Size    % Cumulative  % Kind (class / dict of class)
     0 1000000  33 280000000  74 280000000  74 dict of __main__.Foo
     1 1000000  33  64000000  17 344000000  91 __main__.Foo
     2     169   0  16281480   4 360281480  95 list
     3 1000000  33  16000000   4 376281480  99 __main__.Bar
     4   12284   0    987472   0 377268952  99 str
...
>>> from sys import getsizeof
>>> getsizeof(Right()), getsizeof(Wrong())
(64, 80)
>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000  49 64000000  64  64000000  64 __main__.Foo
     1     169   0 16281480  16  80281480  80 list
     2 1000000  49 16000000  16  96281480  97 __main__.Bar
     3   12284   1   987472   1  97268952  97 str
...
>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085
>>> ns.__dict__
{'b': 'b'}
>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'
>>> nt.quux = 'quux'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'
>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>
>>> swd.__dict__
{'c': 'c'}
__slots__
c = Child()
c.a = 'a'
class AbstractBase:
    __slots__ = ()
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __repr__(self):
        return f'{type(self).__name__}({repr(self.a)}, {repr(self.b)})'
class AbstractBaseC:
    __slots__ = ()
    @property
    def c(self):
        print('getting c!')
        return self._c
    @c.setter
    def c(self, arg):
        print('setting c!')
        self._c = arg
class Base(object): 
    __slots__ = ()
class Base:
    __slots__ = 'foo', 'bar'

class Right(Base):
    __slots__ = 'baz', 

class Wrong(Base):
    __slots__ = 'foo', 'bar', 'baz'        # redundant foo and bar
class BaseA(object): 
    __slots__ = ('a',)

class BaseB(object): 
    __slots__ = ('b',)
class Child(Base):
    __slots__ = ('a',)
class Concretion(AbstractBase, AbstractBaseC):
    __slots__ = 'a b _c'.split()
class Foo(AbstractBase):
    __slots__ = 'a', 'b'
class Foo(object):
    __slots__ = 'bar', 'baz', '__dict__'
class Foo(object): 
    __slots__ = 'foo', 'bar'
class Bar(object):
    __slots__ = 'foo', 'bar' # alas, would work if empty, i.e. ()

>>> class Baz(Foo, Bar): pass
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict
class Foo(object): __slots__ = ()
class Bar(object): __slots__ = ()
class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
b = Baz()
b.foo, b.bar = 'foo', 'bar'
class NoSlots(Child): pass
ns = NoSlots()
ns.a = 'a'
ns.b = 'b'
class SlottedWithDict(Child): 
    __slots__ = ('__dict__', 'b')

swd = SlottedWithDict()
swd.a = 'a'
swd.b = 'b'
swd.c = 'c'
from abc import ABC

class AbstractA(ABC):
    __slots__ = ()

class BaseA(AbstractA): 
    __slots__ = ('a',)

class AbstractB(ABC):
    __slots__ = ()

class BaseB(AbstractB): 
    __slots__ = ('b',)

class Child(AbstractA, AbstractB): 
    __slots__ = ('a', 'b')

c = Child() # no problem!
from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
    """MyNT is an immutable and lightweight object"""
    __slots__ = ()
guppy.hpy().heap()
import timeit

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

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
    def get_set_delete():
        obj.foo = 'foo'
        obj.foo
        del obj.foo
    return get_set_delete

the creation of a __dict__

  • Avoid them if you insist on providing default values via class attributes for instance variables.
  • Avoid them if you want to subclass variable length builtins like long, tuple, or str, and you want to add attributes to them.
  • Avoid them when you want to perform __class__ assignment with another class that doesn't have them (and you can't add them) unless the slot layouts are identical. (I am very interested in learning who is doing this and why.)
  • Denying __dict__ and __weakref__ creation if parent classes deny them and you declare __slots__.
  • Storing value references in slots instead of __dict__.

"You would want to use __slots__ if you are going to instantiate a lot (hundreds, thousands) of objects of the same class."

@NightElfik believe it or not, I contributed to the Python docs on __slots__ about a year back: github.com/python/cpython/pull/1819/files

@Skandix thanks for bringing that typo to my attention, it turned out c was not an instantiation, I probably forgot I was editing that part when I saved it into the post history. It probably would have been caught sooner if I had done the right thing and made the code more copy-pastable... Thanks again!

Abstract Base Classes, for example, from the collections module, are not instantiated, yet __slots__ are declared for them.

Access the regular objects and their __dict__ and inspect again:

And now we have functionality from both via multiple inheritance, and can still deny __dict__ and __weakref__ instantiation:

And trying to assign an unexpected attribute raises an AttributeError because we have prevented the creation of __dict__:

Another purpose of __slots__ is to reduce the space in memory that each object instance takes up.

Avoiding __slots__ because you want to be able to add attributes on the fly is actually not a good reason - just add "__dict__" to your __slots__ if this is required.

Because creating a child class from parents with both non-empty slots fails:

But we don't care about that, that's trivial single inheritance, we need another class we might also inherit from, maybe with a noisy attribute:

Even when non-empty slots are the same for multiple parents, they cannot be used together:

For 64 bit Python, I illustrate the memory consumption in bytes in Python 2.7 and 3.6, for __slots__ and __dict__ (no slots defined) for each point where the dict grows in 3.6 (except for 0, 1, and 2 attributes):

Going out on a limb here: If you're composing mixins or using abstract base classes, which aren't intended to be instantiated, an empty __slots__ in those parents seems to be the best way to go in terms of flexibility for subclassers.

If a user wishes to deny __dict__ or __weakref__ creation, those things must not be available in the parent classes.

If you run into this problem, You could just remove __slots__ from the parents, or if you have control of the parents, give them empty slots, or refactor to abstractions:

If you subclass a built-in type, extra space is automatically added to the instances to accomodate __dict__ and __weakrefs__. (The __dict__ is not initialized until you use it though, so you shouldn't worry about the space occupied by an empty dictionary for each instance you create.) If you don't need this extra space, you can add the phrase "__slots__ = []" to your class.

In Python 2 on Windows I have measured it about 15% faster.

In contrast, a class instance with __slots__ declared to be () (no data) is only 16 bytes, and 56 total bytes with one item in slots, 64 with two.

Instantiate a million of them:

It is true that many Python users aren't writing for reusability, but when you are, having the option to deny unnecessary space usage is valuable.

It then goes on to discuss other ways of accomplishing that perverse goal with Python, not discussing anything to do with __slots__.

Just for completeness of my notes, note that there is a one-time cost per slot in the class's namespace of 64 bytes in Python 2, and 72 bytes in Python 3, because slots use data descriptors like properties, called "members".

Now if both bases had nonempty slots, we couldn't do the below. (In fact, if we wanted, we could have given AbstractBase nonempty slots a and b, and left them out of the below declaration - leaving them in would be wrong):

Or subclass another class that defines __slots__

Or you don't even need to declare __slots__ in your subclass, and you will still use slots from the parents, but not restrict the creation of a __dict__:

Python actually does something similar to this, only creating the __dict__ when it is accessed, but creating lots of objects with no data is fairly ridiculous.

Python doesn't object when you get this wrong (it probably should), problems might not otherwise manifest, but your objects will take up more space than they otherwise should.

Small caveat, you should only declare a particular slot one time in an inheritance tree. For example:

So I would keep this in mind, as it is a solved problem.

So with '__dict__' in slots we lose some of the size benefits with the upside of having dynamic assignment and still having slots for the names we do expect.

So, in spite of smaller dicts in Python 3, we see how nicely __slots__ scale for instances to save us memory, and that is a major reason you would want to use __slots__.

The biggest caveat is for multiple inheritance - multiple "parent classes with nonempty slots" cannot be combined.

The creator of Python, Guido van Rossum, states that he actually created __slots__ for faster attribute access.

The current top answers cite outdated information and are quite hand-wavy and miss the mark in some important ways.

The first paragraph is half short explanation, half predictive. Here's the only part that actually answers the question

The namedtuple builtin make immutable instances that are very lightweight (essentially, the size of tuples) but to get the benefits, you need to do it yourself if you subclass them:

The proper use of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. This saves the overhead of one dict for every object that uses slots

The second half is wishful thinking, and off the mark:

The second paragraph oversimplifies and misses actual reasons to avoid __slots__. The below is not a real reason to avoid slots (for actual reasons, see the rest of my answer above.):

The slotted access is almost 30% faster in Python 3.5 on Ubuntu.

The space saved over using __dict__ can be significant.

The space savings is from

The special attribute __slots__ allows you to explicitly state which instance attributes you expect your object instances to have, with the expected results:

The third paragraph is more wishful thinking. Together it is mostly off-the-mark content that the answerer didn't even author and contributes to ammunition for critics of the site.

There are a lot of details if you wish to keep reading.

They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies.

This is actually incorrect. This message comes from the oldest protocol, which is the default. You can select the latest protocol with the -1 argument. In Python 2.7 this would be 2 (which was introduced in 2.3), and in 3.6 it is 4.

To accommodate this restriction, follow best practices: Factor out all but one or all parents' abstraction which their concrete class respectively and your new concrete class collectively will inherit from - giving the abstraction(s) empty slots (just like abstract base classes in the standard library).

To allow __dict__ creation while subclassing slotted objects, just add '__dict__' to the __slots__ (note that slots are ordered, and you shouldn't repeat slots that are already in parent classes):

To demonstrate, first, let's create a class with code we'd like to use under multiple inheritance

To deny the creation of a __dict__, you must subclass object:

To verify this, using the Anaconda distribution of Python 2.7 on Ubuntu Linux, with guppy.hpy (aka heapy) and sys.getsizeof, the size of a class instance without __slots__ declared, and nothing else, is 64 bytes. That does not include the __dict__. Thank you Python for lazy evaluation again, the __dict__ is apparently not called into existence until it is referenced, but classes without data are usually useless. When called into existence, the __dict__ attribute is a minimum of 280 bytes additionally.

We could use the above directly by inheriting and declaring the expected slots:

When pickling a slotted object, you may find it complains with a misleading TypeError:

When you inherit from an object that isn't slotted, you get the same sort of semantics when you use __slots__ - names that are in __slots__ point to slotted values, while any other values are put in the instance's __dict__.

While this is sometimes a useful optimization, it would be completely unnecessary if the Python interpreter was dynamic enough so that it would only require the dict when there actually were additions to the object.

You can allow __dict__ creation by leaving off __slots__ = (), but you can't use non-empty __slots__ with subtypes of tuple.

You can similarly add __weakref__ to __slots__ explicitly if you need that feature.

You don't have to have slots - so if you add them, and remove them later, it shouldn't cause any problems.

You may be able to tease out further caveats from the rest of the __slots__ documentation (the 3.7 dev docs are the most current), which I have made significant recent contributions to.

and

and now:

in Python 2.7:

in Python 3.6

wow, one hell of an answer - thanks! However, I didn't catched the class Child(BaseA, BaseB): __slots__ = ('a', 'b') example with the empy-slot-parents. Why is here a dictproxy created instead of raising an AttributeError for c?

Note
Rectangle 27 0

python Usage of __slots__?


'__dict__'
>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342
>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'
>>> c = Child()
>>> c.a = 'a'
>>> c.b = 'b'
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'
>>> class BaseA(object): __slots__ = ()
>>> class BaseB(object): __slots__ = ()
>>> class Child(BaseA, BaseB): __slots__ = ('a', 'b')
>>> c = Child
>>> c.a = 'a'
>>> c.b = 'b'
>>> c.c = 'c'
>>> c.__dict__
<dictproxy object at 0x10C944B0>
>>> c.__dict__['c']
'c'
>>> class BaseA(object): __slots__ = ('a',)
>>> class BaseB(object): __slots__ = ('b',)
>>> class Child(BaseA, BaseB): __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
>>> class Foo(object): __slots__ = ()
>>> class Bar(object): __slots__ = ()
>>> class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
>>> b = Baz()
>>> b.foo, b.bar = 'foo', 'bar'
>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()
>>> class NoSlots(Child): pass
>>> ns = NoSlots()
>>> ns.a = 'a'
>>> ns.b = 'b'
>>> ns.__dict__
{'b': 'b'}
>>> foo = Foo()
>>> foo.boink = 'boink'
>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]
>>> for f in foos:
...     f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
 Index  Count   %      Size    % Cumulative  % Kind (class / dict of class)
     0 1000000  33 280000000  74 280000000  74 dict of __main__.Foo
     1 1000000  33  64000000  17 344000000  91 __main__.Foo
     2     169   0  16281480   4 360281480  95 list
     3 1000000  33  16000000   4 376281480  99 __main__.Bar
     4   12284   0    987472   0 377268952  99 str
...
>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000  49 64000000  64  64000000  64 __main__.Foo
     1     169   0 16281480  16  80281480  80 list
     2 1000000  49 16000000  16  96281480  97 __main__.Bar
     3   12284   1   987472   1  97268952  97 str
...
>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085
>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'
>>> nt.quux = 'quux'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'
>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>
__slots__
attrs  __slots__    no slots declared + __dict__
none       16        64 (+ 280 if __dict__ referenced)
one        56        64 + 280
two        64        64 + 280
six        96        64 + 1048
22        224        64 + 3352
class Base(object): 
    __slots__ = ()
class Child(Base):
    __slots__ = ('a',)
class Foo(object):
    __slots__ = 'bar', 'baz', '__dict__'
class SlottedWithDict(Child): 
    __slots__ = ('__dict__', 'b')

>>> swd = SlottedWithDict()
>>> swd.a = 'a'
>>> swd.b = 'b'
>>> swd.c = 'c'
>>> swd.__dict__
{'c': 'c'}
from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
    """MyNT is an immutable and lightweight object"""
    __slots__ = ()
guppy.hpy().heap()
import timeit

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

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
    def get_set_delete():
        obj.foo = 'foo'
        obj.foo
        del obj.foo
    return get_set_delete

the creation of a __dict__

  • Avoid them for parent classes in the case of multiple inheritance - you can reinsert them for a child where you have a lot of instances (see previous section for recommendation).
  • Avoid them if you insist on providing default values via class attributes for instance variables.
  • Avoid them if you want to subclass variable length builtins like long, tuple, or str, and you want to add attributes to them.
  • Avoid them when you want to perform __class__ assignment with another class that doesn't have them (and you can't add them) unless the slot layouts are identical. (I am very interested in learning who is doing this and why.)
  • Denying __dict__ and __weakref__ creation if parent classes deny them and you declare __slots__.
  • Storing value references in slots instead of __dict__.

"You would want to use __slots__ if you are going to instantiate a lot (hundreds, thousands) of objects of the same class."

Abstract Base Classes, for example, from the collections module, are not instantiated, yet __slots__ are declared for them.

Access the regular objects and their __dict__ and inspect again:

And trying to assign an unexpected attribute raises an AttributeError because we have prevented the creation of __dict__:

Another purpose of __slots__ is to reduce the space in memory that each object instance takes up.

Avoiding __slots__ because you want to be able to add attributes on the fly is actually not a good reason - just add "__dict__" to your __slots__ if this is required.

Even when non-empty slots are the same for multiple parents, they cannot be used together:

Going out on a limb here: If you're composing mixins or using abstract base classes, which aren't intended to be instantiated, an empty __slots__ in those parents seems to be the best way to go in terms of flexibility for subclassers.

I tested when my particular implementation of dicts size up by enumerating alphabet characters into a dict, and on the sixth item it climbs to 1048, 22 to 3352, then 85 to 12568 (rather impractical to put that many attributes on a single class, probably violating the single responsibility principle there.)

If a user wishes to deny __dict__ or __weakref__ creation, those things must not be available in the parent classes.

If you run into this problem, just remove __slots__, and put it back in where you have a lot of instances.

If you subclass a built-in type, extra space is automatically added to the instances to accomodate __dict__ and __weakrefs__. (The __dict__ is not initialized until you use it though, so you shouldn't worry about the space occupied by an empty dictionary for each instance you create.) If you don't need this extra space, you can add the phrase "__slots__ = []" to your class.

In Python 2 on Windows I have measured it about 15% faster.

In contrast, a class instance with __slots__ declared to be () (no data) is only 16 bytes, and 56 total bytes with one item in slots, 64 with two.

Instantiate a million of them:

It is true that many Python users aren't writing for reusability, but when you are, having the option to deny unnecessary space usage is valuable.

It then goes on to discuss other ways of accomplishing that perverse goal with Python, not discussing anything to do with __slots__.

Or subclass another class that defines __slots__

Or you don't even need to declare __slots__ in your subclass, and you will still use slots from the parents, but not restrict the creation of a __dict__:

Python actually does something similar to this, only creating the __dict__ when it is accessed, but creating lots of objects with no data is fairly ridiculous.

So I would keep this in mind, as it is a solved problem.

So we see how nicely __slots__ scale for instances to save us memory, and that is the reason you would want to use __slots__.

So with '__dict__' in slots we lose some of the size benefits with the upside of having dynamic assignment and still having slots for the names we do expect.

The biggest caveat is for multiple inheritance - multiple "parent classes with nonempty slots" cannot be combined. To accomodate this restriction, follow best practices: Factor out all but one or all parents' abstraction which their concrete class respectively and your new concrete class collectively will inherit from - giving the abstraction(s) empty slots (just like abstract base classes in the standard library).

The creator of Python, Guido van Rossum, states that he actually created __slots__ for faster attribute access.

The current top answers cite outdated information and are quite hand-wavy and miss the mark in some important ways.

The first paragraph is half short explanation, half predictive. Here's the only part that actually answers the question

The namedtuple builtin make immutable instances that are very lightweight (essentially, the size of tuples) but to get the benefits, you need to do it yourself if you subclass them:

The proper use of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. This saves the overhead of one dict for every object that uses slots

The second half is wishful thinking, and off the mark:

The second paragraph oversimplifies and misses actual reasons to avoid __slots__. The below is not a real reason to avoid slots (for actual reasons, see the rest of my answer above.):

The slotted access is almost 30% faster in Python 3.5 on Ubuntu.

The space saved over using __dict__ can be significant.

The space savings is from

The special attribute __slots__ allows you to explicitly state which instance attributes you expect your object instances to have, with the expected results:

The third paragraph is more wishful thinking. Together it is mostly off-the-mark content that the answerer didn't even author and contributes to ammunition for critics of the site.

There are a lot of details if you wish to keep reading.

They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies.

This is actually incorrect. This message comes from the oldest protocol, which is the default. You can select the latest protocol with the -1 argument. In Python 2.7 this would be 2 (which was introduced in 2.3), and in 3.6 it is 4.

To allow __dict__ creation while subclassing slotted objects, just add '__dict__' to the __slots__ (note that slots are ordered, and you shouldn't repeat slots that are already in parent classes):

To deny the creation of a __dict__, you must subclass object:

To verify this, using the Anaconda distribution of Python 2.7 on Ubuntu Linux, with guppy.hpy (aka heapy) and sys.getsizeof, the size of a class instance without __slots__ declared, and nothing else, is 64 bytes. That does not include the __dict__. Thank you Python for lazy evaluation again, the __dict__ is apparently not called into existence until it is referenced, but classes without data are usually useless. When called into existence, the __dict__ attribute is a minimum of 280 bytes additionally.

When pickling a slotted object, you may find it complains with a misleading TypeError:

When you inherit from an object that isn't slotted, you get the same sort of semantics when you use __slots__ - names that are in __slots__ point to slotted values, while any other values are put in the instance's __dict__.

While this is sometimes a useful optimization, it would be completely unnecessary if the Python interpreter was dynamic enough so that it would only require the dict when there actually were additions to the object.

You can allow __dict__ creation by leaving off __slots__ = (), but you can't use non-empty __slots__ with subtypes of tuple.

You can similarly add __weakref__ to __slots__ explicitly if you need that feature.

You don't have to have slots - so if you add them, and remove them later, it shouldn't cause any problems.

You may be able to tease out further caveats from the rest of the __slots__ documentation (the 3.7 dev docs are the most current), which I have made significant recent contributions to.

and

and now:

in Python 2.7:

in Python 3.6

Note
Rectangle 27 0

python Usage of __slots__?


Each python object has a __dict__ atttribute 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.

However, when you use __slots__, any object created for that class won't have a __dict__ attribute. Instead, all attribute access is done directly via pointers.

No, an instance of a class with __slots__ defined is not like a C-style structure. There is a class-level dictionary mapping attribute names to indexes, otherwise the following would not be possible: class A(object): __slots__= "value",\n\na=A(); setattr(a, 'value', 1) I really think this answer should be clarified (I can do that if you want). Also, I'm not certain that instance.__hidden_attributes[instance.__class__[attrname]] is faster than instance.__dict__[attrname].

So if want a C style structure rather than a full fledged class you can use __slots__ for compacting size of the objects & reducing attribute access time. A good example is a Point class containing attributes x & y. If you are going to have a lot of points, you can try using __slots__ in order to conserve some memory.

Note
Rectangle 27 0

python Usage of __slots__?


I'd like to see some elaboration on the "static typing"/decorator point, sans pejoratives. Quoting absent third parties is unhelpful. __slots__ doesn't address the same issues as static typing. For example, in C++, it is not the declaration of a member variable is being restricted, it is the assignment of an unintended type (and compiler enforced) to that variable. I'm not condoning the use of __slots__, just interested in the conversation. Thanks!

Making CPython smart enough to handle saving space without __slots__ is a major undertaking, which is probably why it is not on the list of changes for P3k (yet).

Python 3.3 fiinally got around to sme of the meory saving without __slots__by the use of shared key dictionaries for instances: python.org/dev/peps/pep-0412

The proper use of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. [This use of __slots__ eliminates the overhead of one dict for every object.] While this is sometimes a useful optimization, it would be completely unnecessary if the Python interpreter was dynamic enough so that it would only require the dict when there actually were additions to the object.

Unfortunately there is a side effect to slots. They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies. This is bad, because the control freaks should be abusing the metaclasses and the static typing weenies should be abusing decorators, since in Python, there should be only one obvious way of doing something.

Note
Rectangle 27 0

python Usage of __slots__?


from peak.util.proxies import ObjectWrapper

class Original(object):
    def __init__(self):
        self.name = 'The Original'

class ProxyOriginal(ObjectWrapper):

    __slots__ = ['proxy_name']

    def __init__(self, subject, proxy_name):
        # proxy_info attributed added directly to the
        # Original instance, not the ProxyOriginal instance
        self.proxy_info = 'You are proxied by {}'.format(proxy_name)

        # proxy_name added to ProxyOriginal instance, since it is
        # defined in __slots__
        self.proxy_name = proxy_name

        super(ProxyOriginal, self).__init__(subject)

if __name__ == "__main__":
    original = Original()
    proxy = ProxyOriginal(original, 'Proxy Overlord')

    # Both statements print "The Original"
    print "original.name: ", original.name
    print "proxy.name: ", proxy.name

    # Both statements below print 
    # "You are proxied by Proxy Overlord", since the ProxyOriginal
    # __init__ sets it to the original object 
    print "original.proxy_info: ", original.proxy_info
    print "proxy.proxy_info: ", proxy.proxy_info

    # prints "Proxy Overlord"
    print "proxy.proxy_name: ", proxy.proxy_name
    # Raises AttributeError since proxy_name is only set on 
    # the proxy object
    print "original.proxy_name: ", proxy.proxy_name

Another somewhat obscure use of __slots__ is to add attributes to an object proxy from the ProxyTypes package, formerly part of the PEAK project. Its ObjectWrapper allows you to proxy another object, but intercept all interactions with the proxied object. It is not very commonly used (and no Python 3 support), but we have used it to implement a thread-safe blocking wrapper around an async implementation based on tornado that bounces all access to the proxied object through the ioloop, using thread-safe concurrent.Future objects to synchronise and return results.

By default any attribute access to the proxy object will give you the result from the proxied object. If you need to add an attribute on the proxy object, __slots__ can be used.

Note
Rectangle 27 0

python Usage of __slots__?


Now this may not be directly related to the OPs question. It is related more to building extensions than it does to using the slots syntax on an object. But it does help complete the picture for the usage of slots and some of the reasoning behind them.

Slots are very useful for library calls to eliminate the "named method dispatch" when making function calls. This is mentioned in the SWIG documentation. For high performance libraries that want to reduce function overhead for commonly called functions using slots is much faster.

Note
Rectangle 27 0

python Usage of __slots__?


>>> class Test(object):   #Must be new-style class!
...  __slots__ = ['x', 'y']
... 
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', 
 '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']

In addition to the other answers, here is an example of using __slots__:

So, to implement __slots__, it only takes an extra line (and making your class a new-style class if it isn't already). This way you can reduce the memory footprint of those classes 5-fold, at the expense of having to write custom pickle code, if and when that becomes necessary.

Note