Python Language Descriptors and Dotted Lookups


Example

Descriptors are objects that are (usually) attributes of classes and that have any of __get__, __set__, or __delete__ special methods.

Data Descriptors have any of __set__, or __delete__

These can control the dotted lookup on an instance, and are used to implement functions, staticmethod, classmethod, and property. A dotted lookup (e.g. instance foo of class Foo looking up attribute bar - i.e. foo.bar) uses the following algorithm:

  1. bar is looked up in the class, Foo. If it is there and it is a Data Descriptor, then the data descriptor is used. That's how property is able to control access to data in an instance, and instances cannot override this. If a Data Descriptor is not there, then

  2. bar is looked up in the instance __dict__. This is why we can override or block methods being called from an instance with a dotted lookup. If bar exists in the instance, it is used. If not, we then

  3. look in the class Foo for bar. If it is a Descriptor, then the descriptor protocol is used. This is how functions (in this context, unbound methods), classmethod, and staticmethod are implemented. Else it simply returns the object there, or there is an AttributeError