An interactive session shows that the$_{Person}$ class has called$_{__set_name__()}$ so that the field names would be recorded. Here we call vars() to look up the descriptor without triggering it: The new class now logs access to both name and age : The two Person instances contain only the private names: A descriptor is what we call any object that defines$_{__get__()}$ ,$_{__set__()}$ , or$_{__delete__()}$ . Optionally, descriptors can have a$_{__set_name__()}$ method. This is only used in cases where a descriptor needs to know either the class where it was created or the name of class variable it was assigned to. (This method, if present, is called even if the class is not a descriptor.) Descriptors get invoked by the dot “operator” during attribute lookup. If a descriptor is accessed indirectly with vars(some_class)[descriptor_name] , the descriptor instance is returned without invoking it. Descriptors only work when used as class variables. When put in instances, they have no effect. The main motivation for descriptors is to provide a hook allowing objects stored in class variables to control what happens during attribute lookup. Traditionally, the calling class controls what happens during lookup. Descriptors invert that relationship and allow the data being looked-up to have a say in the matter. Descriptors are used throughout the language. It is how functions turn into bound methods. Common tools like classmethod() , staticmethod() , property() , and functools.cached_property() are all implemented as descriptors. In this example, we create a practical and powerful tool for locating notoriously hard to find data corruption bugs. 2 Complete Practical Example 1.5 Closing thoughts >>> vars(pete) {'_name': 'Peter P', '_age': 10} >>> vars(kate) {'_name': 'Catherine C', '_age': 20} >>> pete =Person('Peter P',10 ) INFO:root:Updating 'name' to 'Peter P' INFO:root:Updating 'age' to 10 >>> kate =Person('Catherine C ',20 ) INFO:root:Updating 'name' to 'Catherine C' INFO:root:Updating 'age' to 20 >>> vars(vars(Person)[ 'name']) {'public_name': 'name', 'private_name': '_name'} >>> vars(vars(Person)[ 'age']) {'public_name': 'age', 'private_name': '_age'} 6