Para soportar la asignación de atributos arbitrarios, un objeto necesita un __dict__: un dictado asociado con el objeto, donde se pueden almacenar atributos arbitrarios. De lo contrario, no hay ningún lugar donde colocar nuevos atributos.
Una instancia de objectqué no llevar un __dict__- si lo hiciera, antes de que el problema de la dependencia circular horribles (ya que dict, como casi todo lo demás, hereda de object;-), esto sería cargar a cada objeto en Python con un diccionario, lo que significaría una sobrecarga de muchos bytes por objeto que actualmente no tiene o necesita un dict (esencialmente, todos los objetos que no tienen atributos asignables arbitrariamente no tienen o necesitan un dict).
Por ejemplo, usando el excelente pymplerproyecto (puede obtenerlo a través de svn desde aquí ), podemos hacer algunas medidas ...:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
No querría que cada uno intocupe 144 bytes en lugar de solo 16, ¿verdad? -)
Ahora, cuando haces una clase (heredando de lo que sea), las cosas cambian ...:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
... el __dict__ se añade ahora (además, un poco más sobrecarga) - por lo que una dintinstancia puede tener atributos arbitrarios, pero que pagar un costo de un espacio para que la flexibilidad.
Entonces, ¿qué pasaría si quisieras ints con solo un atributo adicional foobar...? Es una necesidad poco común, pero Python ofrece un mecanismo especial para ese propósito ...
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
... no es bastante tan pequeño como una int, que importa! (o incluso los dos ints, uno el selfy otro el self.foobar- el segundo se puede reasignar), pero seguramente mucho mejor que a dint.
Cuando la clase tiene el __slots__atributo especial (una secuencia de cadenas), entonces la classdeclaración (más precisamente, la metaclase predeterminada type) no equipa cada instancia de esa clase con un __dict__(y por lo tanto la capacidad de tener atributos arbitrarios), solo un finito , conjunto rígido de "ranuras" (básicamente lugares que pueden contener una referencia a algún objeto) con los nombres de pila.
A cambio de la flexibilidad perdida, se obtiene una gran cantidad de bytes por ejemplo (probablemente significativas sólo si tiene millones y millones de casos gallivanting alrededor, pero, no son casos de uso para eso).
objecttipo es inmutable y no se pueden agregar nuevos atributos? Esto parece que tendría más sentido.