curious about how functions turn into bound methods or about the implementation of common tools like classmethod() , staticmethod() , property() , and __slots__. 

## 1 Primer 

In this primer, we start with the most basic possible example and then we’ll add new capabilities one by one. 

## 1.1 Simple example: A descriptor that returns a constant 

The Ten class is a descriptor that always returns the constant 10 from its __get__() method: 

classTen : def __get__ (self, obj, objtype = None ): return 10 

To use the descriptor, it must be stored as a class variable in another class: 

classA : x =5 # Regular class attribute y =Ten() # Descriptor instance 

An interactive session shows the difference between normal attribute lookup and descriptor lookup: 

>>> a =A() # Make an instance of class A >>> a.x # Normal attribute lookup 5 >>> a.y # Descriptor lookup 10 

In the$_{a.x}$ attribute lookup, the dot operator finds the key$_{x}$and the value$_{5}$in the class dictionary. In the$_{a.y}$lookup, the dot operator finds a descriptor instance, recognized by its$_{__get__}$ method, and calls that method which returns 10 . 

Note that the value$_{10}$ is not stored in either the class dictionary or the instance dictionary. Instead, the value$_{10}$ is computed on demand. 

This example shows how a simple descriptor works, but it isn’t very useful. For retrieving constants, normal attribute lookup would be better. 

In the next section, we’ll create something more useful, a dynamic lookup. 

## 1.2 Dynamic lookups 

Interesting descriptors typically run computations instead of returning constants: 

import os classDirectorySize : def __get__ (self, obj, objtype = None ): return len(os.listdir(obj.dirname)) classDirectory : size =DirectorySize() # Descriptor instance def __init__ (self, dirname): self.dirname =dirname # Regular instance attribute 

