In the Python data model reference section on slots there is a list of notes on using __slots__. I am thoroughly confused by the 1st and 6th items, because they seem to be contradicting each other.
First item:
- When inheriting from a class without
__slots__, the__dict__attribute
of that class will always be
accessible, so a__slots__
definition in the subclass is
meaningless.
Sixth item:
- The action of a
__slots__
declaration is limited to the class
where it is defined. As a result,
subclasses will have a__dict__
unless they also define__slots__
(which must only contain names of any
additional slots).
It seems to me these items could be better worded or shown through code, but I have been trying to wrap my head around this and am still coming up confused. I do understand how __slots__ are supposed to be used, and I am trying to get a better grasp on how they work.
The Question:
Can someone please explain to me in plain language what the conditions are for inheritance of slots when subclassing?
(Simple code examples would be helpful but not necessary.)
As others have mentioned, the sole reason for defining
__slots__is to save some memory, when you have simple objects with a predefined set of attributes and don’t want each to carry around a dictionary. This is meaningful only for classes of which you plan to have many instances, of course.The savings may not be immediately obvious — consider…:
From this, it would seem the with-slots size is larger than the no-slots size! But that’s a mistake, because
sys.getsizeofdoesn’t consider "object contents" such as the dictionary:Since the dict alone takes 140 bytes, clearly the "32 bytes" object
nis alleged to take are not considering all that’s involved in each instance. You can do a better job with third-party extensions such as pympler:This shows much more clearly the memory footprint that’s saved by
__slots__: for a simple object such as this case, it’s a bit less than 200 bytes, almost 2/3 of the object’s overall footprint. Now, since these days a megabyte more or less doesn’t really matter all that much to most applications, this also tells you that__slots__is not worth the bother if you’re going to have just a few thousand instances around at a time — however, for millions of instances, it sure does make a very important difference. You can also get a microscopic speedup (partly due to better cache use for small objects with__slots__):but this is somewhat dependent on Python version (these are the numbers I measure repeatably with 2.5; with 2.6, I see a larger relative advantage to
__slots__for setting an attribute, but none at all, indeed a tiny disadvantage, for getting it).Now, regarding inheritance: for an instance to be dict-less, all classes up its inheritance chain must also have dict-less instances. Classes with dict-less instances are those which define
__slots__, plus most built-in types (built-in types whose instances have dicts are those on whose instances you can set arbitrary attributes, such as functions). Overlaps in slot names are not forbidden, but they’re useless and waste some memory, since slots are inherited:as you see, you can set attribute
aon anABinstance —ABitself only defines slotb, but it inherits slotafromA. Repeating the inherited slot isn’t forbidden:but does waste a little memory:
so there’s really no reason to do it.