From https://stackoverflow.com/a/1529099/156458
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 fromobject
;-), 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).
...
When the class has the
__slots__
special attribute (a sequence of strings), then theclass
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.
If an object doesn't have __dict__
, must its class have a __slots__
attribute?
For example, an instance of object
doesn't have a __dict__
:
>>> object().__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'
but it doesn't have __slots__
either:
>>> object.__slots__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__slots__'
Do object
instances have any attributes at all?
How many possibilities are there:
__dict__
, and its class has __dict__
but no __slots__
__dict__
, and its class has __slots__
__dict__
, and its class doesn't have __slots__
?Is it possible to tell if an object has __dict__
from its class?
if its class has __slots__
, then it doesn't have __dict__
, correct?
if its class doesn't have __slots__
, how can I tell if it has __dict__
or not?
All objects in Python have an attribute __dict__, which is a dictionary object containing all attributes defined for that object itself. The mapping of attributes with its values is done to generate a dictionary.
__slots__ is a class variable. If you have more than one instance of your class, any change made to __slots__ will show up in every instance. You cannot access the memory allocated by the __slots__ declaration by using subscription. You will get only what is currently stored in the list.
The proper use of __slots__ is to save space in objects. Instead of having a dynamic dict that allows adding attributes to objects at anytime, there is a static structure which does not allow additions after creation. [This use of __slots__ eliminates the overhead of one dict for every object.]
object.__dict__ A dictionary or other mapping object used to store an object's (writable) attributes.
For user defined classes (defined using the class
keyword in regular Python code), a class will always have __slots__
on the class, __dict__
on the instance, or both (if one of the slots defined is '__dict__'
, or one of the user defined classes in an inheritance chain defines __slots__
and another one does not, creating __dict__
implicitly). So that's three of four possibilities covered for user defined classes.
Edit: A correction: Technically, a user-defined class could have neither; the class would be defined with __slots__
, but have it deleted after definition time (the machinery that sets up the type doesn't require __slots__
to persist after the class definition finishes). No sane person should do this, and it could have undesirable side-effects (full behavior untested), but it's possible.
For built-in types, at least in the CPython reference interpreter, they're extremely unlikely to have __slots__
(if they did, it would be to simulate a user-defined class, defining it doesn't actually do anything useful). A built-in type typically stores its attributes as raw C level values and pointers on a C level struct, optionally with explicitly created descriptors or accessor methods, which eliminates the purpose of __slots__
, which are just a convenient limited purpose equivalent of such struct games for user defined classes. __dict__
is opt-in for built-in types, not on by default (though the opt-in process is fairly easy; you need to put a PyObject*
entry somewhere in the struct and provide the offset to it in the type definition).
To be clear, __dict__
need not appear on the class for it to appear on its instances; __slots__
is class level, and can suppress the __dict__
on the instance, but has no effect on whether the class itself has a __dict__
; user defined classes always have __dict__
, but their instances won't if you're careful to use __slots__
appropriately.
So in short:
(Sane) User defined classes have at least one of __dict__
(on the instances) or __slots__
(on the class), and can have both. Insane user defined classes could have neither, but only a deranged developer would do it.
Built-in classes often have neither, may provide __dict__
, and almost never provide __slots__
as it is pointless for them.
Examples:
# Class has __slots__, instances don't have __dict__
class DictLess:
__slots__ = ()
# Instances have __dict__, class lacks __slots__
class DictOnly:
pass
# Class has __slots__, instances have __dict__ because __slots__ declares it
class SlottedDict:
__slots__ = '__dict__',
# Class has __slots__ without __dict__ slot, instances have it anyway from unslotted parent
class DictFromParent(DictOnly):
__slots__ = ()
# Complete insanity: __slots__ takes effect at class definition time, but can
# be deleted later, without changing the class behavior:
class NoSlotNoDict:
__slots__ = ()
del NoSlotNoDict.__slots__
# Instances have no __dict__, class has no __slots__ but acts like it does
# (the machinery to make it slotted isn't undone by deleting __slots__)
# Please, please don't actually do this
# Built-in type without instance __dict__ or class defined __slots__:
int().__dict__ # Raises AttributeError
int.__slots__ # Also raises AttributeError
# Built-in type that opts in to __dict__ on instances:
import functools
functools.partial(int).__dict__ # Works fine
functools.partial.__slots__ # Raises AttributeError
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With