To support arbitrary attribute assignment, an object requires a __dict__ : dict associated with the object, where arbitrary attributes can be stored. Otherwise, there is nowhere to add new attributes.
The object instance does not transfer __dict__ - if it did, it faces a terrible circular dependency problem (since dict , like everything else, inherits from object ;-), this would saddle every Python object using dict, which would mean overhead for many bytes per object that currently does not have or needs a dict (in fact, all objects that do not have arbitrary attributes are not needed or need a dict).
For example, using the excellent pympler project (you can get it via svn from here ), we can take some measurements ..
>>> from pympler import asizeof >>> asizeof.asizeof({}) 144 >>> asizeof.asizeof(23) 16
You do not want each int occupy 144 bytes instead of 16, right? -)
Now, when you create a class (inheriting from something), things change ...:
>>> class dint(int): pass ... >>> asizeof.asizeof(dint(23)) 184
... now __dict__ added (plus, a bit more overhead), so the dint instance can have arbitrary attributes, but you pay for it flexibility.
So, what if you wanted an int with only one additional attribute foobar ...? This is a rare necessity, but Python offers a special mechanism for this purpose ...
>>> class fint(int): ... __slots__ = 'foobar', ... def __init__(self, x): self.foobar=x+100 ... >>> asizeof.asizeof(fint(23)) 80
... not quite as small as int , mind you! (or even two int s, one self and one self.foobar - the second can be reassigned), but, of course, much better than a dint .
When a class has a special __slots__ attribute (a sequence of strings), the class operator (more precisely, the default metaclass, type ) does not equip each instance of this class with __dict__ (and, therefore, the ability to have arbitrary attributes), just a finite hard set of โslotsโ (mainly places, each of which may contain one link to an object) with the specified names.
Instead of losing flexibility, you get a lot of bytes per instance (maybe this only makes sense if you have millions of instances galvanizing around, but there are use cases for that).