Slots seem to be poorly documented. What they do is simple, but whether they are used is tricky. This is a little mini-post on slots.
Immutable list of instance attributes
Slots replace the mutable dictionary of instance level attributes (
__dict__) that most subclasses have with an immutable one. For example:
class NoSlots(object): pass class Slots(object): __slots__ = ('x',) pass
We need an instance, as class level attributes (shared by all instances of a class) are not affected by
noslots = NoSlots() slots = Slots()
noslots.x = 2 slots.x = 2 noslots.y = 3
slots.y = 3 # Fails
Since there is no
__dict__ to store the instance variable
.y in, this is error. This makes
__slots__ a lot like the list of member variables in other languages, and lets you see all the possible instance variables in one place, instead of checking all the methods.
This feature was actually intended, however, to save memory and performance, since each instance now has a specific set of slots they can put variables in, instead of each one tracking the possible variables. However, it doesn’t make much of a difference unless you have a very large number of instances. Python 3.3 reduced the difference even further with key sharing dictionaries. I would argue the previous reason is more important; I’ve caught bugs with misnamed variables when adding slots.
When slots count
Slots only work in a special case: all parent classes have to have
__slots__ too (that is, none of them can have an instance
__dict__). Most or all the builtins do this, so you just need to be careful when subclassing your own or third party library types.
__slots__ combine in an odd way, but it makes sense: A class has it’s own and all parent classes
__slots__ combined. So, for example, look at the following subclass:
class Vector2D(object): __slots__ = ('x','y') class Vector3D(Vector2D): __slots__ = ('z',)
Vector3D has three instance variables, x, y, and z; since it inherits the Vector2D slots. You can’t remove slots (as that would break the class anyway), and you keep the same slots by setting slots to an empty tuple (or similar). If you ignore slots, the class becomes a
class Also2Slots(Vector2D): __slots__= () class NoSlots(Vector2D): pass
Also2Slots().z = 2 # Won't work, slots are x and y
NoSlots().z = 2 # No error!
Have you ever wondered why this doesn’t work:
thing = object() thing.x = 2 # Error!
But this does:
class SubObject(object): pass thing = SubObject() thing.x = 2 # Works!
Now you know,
Side note: In Python 3.3+, the
SimpleNamespaceobject is a lot like
__slots__(and a fancy constructor).