Exercise Answers¶
Page Maps¶
graph LR
family["Python Programming"]
program["Python Meta-Programming"]
section["Descriptors Lookup Attribute Control"]
page["Exercise Answers"]
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"]
Use this page after attempting the exercises yourself. The point is not to match every example literally. The point is to compare your reasoning against answers that keep descriptor mechanics, storage, and ownership boundaries honest.
Answer 1: Build one minimal descriptor on purpose¶
Example answer:
class UpperName:
def __get__(self, obj, owner=None):
if obj is None:
return self
return obj.__dict__.get("_name", "").upper()
Good conclusion:
This is still a descriptor because __get__ alone is enough. It does not need __set__
or __delete__ if the design only cares about reads, and class access returns the
descriptor itself for inspection.
Answer 2: Show precedence with two concrete cases¶
Example answer:
For a data descriptor:
obj.__dict__["value"] = 999does not bypass a descriptor that defines__set__
For a non-data descriptor:
- an instance assignment like
obj.value = 999places a same-named entry inobj.__dict__ - later reads return that instance value instead of calling the descriptor
Good conclusion:
The outcomes differ because data descriptors beat the instance dictionary, while non-data descriptors yield to it.
Answer 3: Explain ordinary method binding¶
Example answer:
Class.methodreturns the underlying function objectobj.methodreturns a bound method object- the bound method exposes
__func__for the original function and__self__for the instance
Good conclusion:
Method binding is descriptor behavior, not special syntax magic. Functions on classes are
non-data descriptors whose __get__ logic produces bound methods on instance access.
Answer 4: Build one reusable validating field¶
Example answer:
class PositiveInt:
def __set_name__(self, owner, name):
self.public_name = name
self.private_name = f"_{name}"
def __get__(self, obj, owner=None):
if obj is None:
return self
return obj.__dict__.get(self.private_name, 0)
def __set__(self, obj, value):
number = int(value)
if number < 0:
raise ValueError(f"{self.public_name} must be non-negative")
obj.__dict__[self.private_name] = number
Good conclusion:
__set_name__ removes hard-coded field names, and the stored values live on the instance,
not on the descriptor object.
Answer 5: Reject one bad storage design¶
Example answer:
Broken design:
Leak example:
- assigning through one instance changes what another instance later reads
Safer redesign:
- store by private name in
obj.__dict__ - or use
WeakKeyDictionarywhen slotted instances need external storage
Good conclusion:
The descriptor object is shared at the class level, so descriptor-held field values are usually shared-state bugs waiting to happen.
Answer 6: Place one field rule on the ownership ladder¶
Example answer:
Requirement:
- every
emailfield across several model classes should normalize to lowercase and reject blank values
Best owner:
- reusable descriptor
Rejected stronger option:
- a metaclass is unnecessary because the problem is field behavior, not class-creation control
Rejected weaker option:
- a single property on one class would not scale cleanly across several repeated fields
Good conclusion:
Strong answers justify the chosen owner by naming both the repeated field semantics and the clearer alternatives that were rejected.
What strong Module 07 answers have in common¶
Across the whole set, strong answers share the same habits:
- they explain lookup mechanically
- they distinguish data descriptors from non-data descriptors precisely
- they keep state ownership explicit
- they choose descriptor power only when a field-level boundary truly needs it
If an answer still sounds like "descriptors are advanced so they fit here," revise it until you can say exactly what attribute rule they own and why.