Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python descriptors: field validation and attribute precedence

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A descriptor is a class attribute whose type implements attribute-access hooks such as __get__ or __set__.

Download Python source kit

Operation contract

The managed quantity accepts exact integers between zero and one thousand. The descriptor records its field name during class creation, then validates before writing instance storage. Because it defines __set__, normal attribute lookup gives this data descriptor precedence over an instance dictionary entry with the public name. That prevents an accidental public-name assignment from bypassing this particular access path.

Failure and ownership boundary

This is an application convention, not a security boundary. A caller with the object can edit its private dictionary directly or replace class behavior. Class access returns the descriptor itself; forgetting that case can attempt to read storage from None. Python properties: validate mutation at the public attribute boundary uses the same attribute-management mechanism for a single field.

Working program

python
class BoundedQuantity:
    def __set_name__(self, owner, name):
        self.storage = "_" + name
    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return instance.__dict__[self.storage]
    def __set__(self, instance, value):
        if type(value) is not int or not 0 <= value <= 1000:
            raise ValueError("quantity out of range")
        instance.__dict__[self.storage] = value

class DispatchLine:
    quantity = BoundedQuantity()
    def __init__(self, quantity):
        self.quantity = quantity

line = DispatchLine(12)
try:
    line.quantity = True
except ValueError:
    print("boolean rejected")
line.__dict__["quantity"] = 999
print(line.quantity)
print(isinstance(DispatchLine.quantity, BoundedQuantity))

Output

Output
boolean rejected
12
True

Costs and limits

For these small integers, validation has bounded work and each instance stores one field value. Attribute hook calls add dispatch overhead; benchmark the application rather than assigning a universal descriptor cost.

Common Mistakes

  • Handle class access where instance is None.
  • Descriptors do not prevent a caller from changing private storage.

Connected lessons

Python properties: validate mutation at the public attribute boundary, Python classes: keep instance state separate from class state, Python super and method resolution: cooperate across mixins.

Follow the related contract

Python staticmethod and classmethod: choose the bound receiver, Python object lookup interview: descriptor precedence before instance state.

python
descriptors
Storage details