Module 07: Descriptors, Lookup, and Attribute Control¶
Page Maps¶
graph LR
family["Python Programming"]
program["Python Meta-Programming"]
section["Descriptors Lookup Attribute Control"]
page["Module 07: Descriptors, Lookup, and Attribute Control"]
capstone["Capstone evidence"]
family --> program --> section --> page
page -.applies in.-> capstone
flowchart LR
orient["Orient on the page map"] --> read["Read the main claim and examples"]
read --> inspect["Inspect the related code, proof, or capstone surface"]
inspect --> verify["Run or review the verification path"]
verify --> apply["Apply the idea back to the module and capstone"]
Module 07 is where attribute access stops feeling intuitive and starts becoming a visible runtime protocol. The goal is not to memorize descriptor trivia. The goal is to understand what actually happens when Python reads, writes, or deletes an attribute, and to decide when a descriptor is the honest owner of that behavior.
This module now uses the same ten-file learning surface as the deep-dive series so the overview, five cores, worked example, practice set, answers, and glossary each have one clear job.
What this module is for¶
By the end of Module 07, you should be able to explain five things clearly:
- what makes an object a descriptor and when Python invokes it
- why data descriptors and non-data descriptors have different precedence
- how plain functions become bound methods through descriptor behavior
- where reusable field descriptors should keep per-instance state
- when a descriptor is the right owner instead of a property, wrapper, or wider class hook
Keep these pages open¶
The ten files in this module¶
- Overview (
index.md) - Descriptor Protocol and
__set_name__ - Data and Non-Data Descriptor Precedence
- Functions, Binding, and Method Descriptors
- Reusable Field Descriptors and Storage
- Descriptor Boundaries and Attribute Ownership
- Worked Example: Building a Unit-Aware Quantity Descriptor
- Exercises
- Exercise Answers
- Glossary
How to use the file set¶
| If you need to... | Start here |
|---|---|
understand the full descriptor protocol and the role of __set_name__ |
Descriptor Protocol and __set_name__ |
| make sense of shadowing and precedence during lookup | Data and Non-Data Descriptor Precedence |
| explain how instance methods bind through function descriptors | Functions, Binding, and Method Descriptors |
| build reusable validated fields without shared-state bugs | Reusable Field Descriptors and Storage |
| decide whether attribute behavior truly belongs to a descriptor | Descriptor Boundaries and Attribute Ownership |
| see those choices combined in one bounded field system | Worked Example: Building a Unit-Aware Quantity Descriptor |
| pressure-test your understanding before moving into framework-grade descriptor systems | Exercises |
| compare your reasoning against a reference answer | Exercise Answers |
| stabilize the descriptor vocabulary used in this directory | Glossary |
The running question¶
Carry this question through every page:
What belongs to attribute access itself, and what would become more confusing if I hid it behind a wrapper or wider class hook?
Strong Module 07 answers usually mention one or more of these:
- the descriptor protocol on class attributes
- precedence rules between descriptors and instance state
- method binding as non-data descriptor behavior
- per-instance storage that does not leak across objects
- a lower-power decision that rejects unnecessary class-wide machinery
Learning outcomes¶
By the end of this module, you should be able to:
- explain the descriptor protocol without treating it as exotic magic
- predict lookup precedence for data descriptors, non-data descriptors, instance dictionaries, and plain class attributes
- describe how bound methods are created and what
__func__and__self__mean - choose storage patterns for reusable descriptors that keep instance behavior independent
- reject descriptor use when a simpler attribute boundary would be clearer
Exit standard¶
Do not move on until all of these are true:
- you can explain what descriptor methods participate in reads, writes, and deletes
- you can say why data descriptors beat instance dictionaries while non-data descriptors can be shadowed
- you can trace ordinary method binding back to
function.__get__ - you can place one field invariant honestly on the descriptor side of the power ladder
When those feel ordinary, Module 07 has done its job and Module 08 can extend the same ideas into larger descriptor systems.