Can’t set attributes on instance of “object” class

To support arbitrary attribute assignment, an object needs a __dict__: a dict associated with the object, where arbitrary attributes can be stored. Otherwise, there’s nowhere to put new attributes.

An instance of object does not carry around a __dict__ — if it did, before the horrible circular dependence problem (since dict, like most everything else, inherits from object;-), this would saddle every object in Python with a dict, which would mean an overhead of many bytes per object that currently doesn’t have or need a dict (essentially, all objects that don’t have arbitrarily assignable attributes don’t have or need a dict).

For example, using the excellent pympler project (you can get it via svn from here), we can do some measurements…:

>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16

You wouldn’t want every int to take up 144 bytes instead of just 16, right?-)

Now, when you make a class (inheriting from whatever), things change…:

>>> class dint(int): pass
... 
>>> asizeof.asizeof(dint(23))
184

…the __dict__ is now added (plus, a little more overhead) — so a dint instance can have arbitrary attributes, but you pay quite a space cost for that flexibility.

So what if you wanted ints with just one extra attribute foobar…? It’s a rare need, but Python does offer a special mechanism for the purpose…

>>> class fint(int):
...   __slots__ = 'foobar',
...   def __init__(self, x): self.foobar=x+100
... 
>>> asizeof.asizeof(fint(23))
80

…not quite as tiny as an int, mind you! (or even the two ints, one the self and one the self.foobar — the second one can be reassigned), but surely much better than a dint.

When the class has the __slots__ special attribute (a sequence of strings), then the class statement (more precisely, the default metaclass, type) does not equip every instance of that class with a __dict__ (and therefore the ability to have arbitrary attributes), just a finite, rigid set of “slots” (basically places which can each hold one reference to some object) with the given names.

In exchange for the lost flexibility, you gain a lot of bytes per instance (probably meaningful only if you have zillions of instances gallivanting around, but, there are use cases for that).

Leave a Comment