7

In the example below, attribute x is accessed from the slots of the object even though x is present in __dict__ (this is not a typical or probably useful case, but I'm curious):

>>> class C(object):
...     __slots__ = 'x'
...     
>>> class D(C):
...     pass
... 
>>> obj = D()
>>> obj.x = 'Stored in slots'
>>> obj.__dict__
{}
>>> obj.__dict__['x'] = 'stored in __dict__'
>>> obj.x
'Stored in slots'

Is this order of access (slots first) a documented behavior? or simply an implementation detail?

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260

1 Answers1

11

Yes, the __dict__ of an object is only consulted after data descriptors have been consulted. __slots__ attributes are implemented as data descriptors.

See Invoking descriptors:

For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined. A descriptor can define any combination of __get__(), __set__() and __delete__(). If it does not define __get__(), then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary. If the descriptor defines __set__() and/or __delete__(), it is a data descriptor; if it defines neither, it is a non-data descriptor. Normally, data descriptors define both __get__() and __set__(), while non-data descriptors have just the __get__() method. Data descriptors with __set__() and __get__() defined always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.

and from the same page, section on slots:

__slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • I believe this should also be quoted (from [Implementing Descriptors](http://docs.python.org/2/reference/datamodel.html#implementing-descriptors)): "the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents". – Pavel Anossov Feb 28 '13 at 15:29
  • 1
    @PavelAnossov: Not sure what that would add to understanding slots. The slot attributes are implemented as descriptors on the class, and data descriptors come before instance `__dict__` values. That is enough to document this behavior, is it not? – Martijn Pieters Feb 28 '13 at 15:32
  • @PavelAnossov: Yes, sometimes people are confused as to where descriptors are looked up, but that is not at issue here. – Martijn Pieters Feb 28 '13 at 15:33