(continued from previous page) 9 What follows is a more technical tutorial for the mechanics and details of how descriptors work. Defines descriptors, summarizes the protocol, and shows how descriptors are called. Provides an example showing how object relational mappings work. Learning about descriptors not only provides access to a larger toolset, it creates a deeper understanding of how Python works. In general, a descriptor is an attribute value that has one of the methods in the descriptor protocol. Those methods are$_{__get__()}$ ,$_{__set__()}$ , and$_{__delete__()}$ . If any of those methods are defined for an attribute, it is said to be a descriptor. The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with$_{a.__dict__['x']}$ , then$_{type(a).__dict__['x']}$ , and continuing through the method resolution order of$_{type(a)}$ . If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined. Descriptors are a powerful, general purpose protocol. They are the mechanism behind properties, methods, static methods, class methods, and$_{super()}$ . They are used throughout Python itself. Descriptors simplify the underlying C code and offer a flexible set of new tools for everyday Python programs. Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence. If an object defines$_{__set__()}$ or$_{__delete__()}$ , it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are often used for methods but other uses are possible). That is all there is to it. Define any of these methods and an object is considered a descriptor and can override default behavior upon being looked up as an attribute. 3.3 Descriptor protocol 3 Technical Tutorial 3.1 Abstract 3.2 Definition and introduction ValueError: Expected -5 to be at least 0 >>> Component( 'WIDGET','metal','V') # Blocked: 'V' isn't a number Traceback (most recent call last): ... TypeError: Expected 'V' to be an int or float >>> c =Component( 'WIDGET','metal',5) # Allowed: The inputs are valid descr.__get__(self, obj, type=None) -> value descr.__set__(self, obj, value) -> None descr.__delete__(self, obj) -> None