python 37 lines · 8 steps

Building a typed descriptor in Python

A data descriptor that enforces types and runs custom validators on every attribute assignment.

Explained by highlit
1class Typed:
2 """A data descriptor that enforces a type and optional validation."""
3 
4 def __init__(self, expected_type, validator=None):
5 self.expected_type = expected_type
6 self.validator = validator
7 
8 def __set_name__(self, owner, name):
9 self.name = name
10 self.private_name = f"_{name}"
11 
12 def __get__(self, instance, owner=None):
13 if instance is None:
14 return self
15 return getattr(instance, self.private_name)
16 
17 def __set__(self, instance, value):
18 if not isinstance(value, self.expected_type):
19 raise TypeError(
20 f"{self.name!r} must be {self.expected_type.__name__}, "
21 f"got {type(value).__name__}"
22 )
23 if self.validator is not None and not self.validator(value):
24 raise ValueError(f"{value!r} failed validation for {self.name!r}")
25 setattr(instance, self.private_name, value)
26 
27 def __delete__(self, instance):
28 raise AttributeError(f"{self.name!r} cannot be deleted")
29 
30 
31class Account:
32 owner = Typed(str, validator=lambda s: len(s) > 0)
33 balance = Typed((int, float), validator=lambda n: n >= 0)
34 
35 def __init__(self, owner, balance):
36 self.owner = owner
37 self.balance = balance
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Data descriptors intercept attribute access at the class level, letting you centralize validation logic instead of scattering checks across setters.
  2. 2__set_name__ hands each descriptor its own attribute name automatically, so one descriptor class can be reused for many fields.
  3. 3Storing values under a per-name private attribute keeps the descriptor's bookkeeping separate from the public attribute it guards.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a typed descriptor in Python — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code