Skip to main content

Properties: Controlled Attributes

intermediate13 min readLesson 63 of 169

Validate on assignment with @property โ€” keep the simple attribute syntax.

Beginners write obj.age = 300 and hope for the best. Intermediate developers make invalid states impossible โ€” without giving up the simple attribute syntax. That is exactly what @property is for:

class Person:
    def __init__(self, age):
        self.age = age          # goes through the setter below!

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if not (0 <= value <= 150):
            raise ValueError(f"age must be 0..150, got {value}")
        self._age = value

Now Person(-5) raises immediately, and so does p.age = -1. The convention: the public name age is a property; the raw value lives in _age (single underscore = internal).

Read-only computed properties

A property with only a getter is read-only โ€” perfect for values derived from real state:

class Rectangle:
    def __init__(self, w, h):
        self.w, self.h = w, h

    @property
    def area(self):
        return self.w * self.h      # no setter: cannot assign

r.area = 99 now raises AttributeError โ€” a good kind of error, because area was never independent state.

Why properties instead of get_x()/set_x()?

Python style is to expose attributes directly and upgrade to properties later if rules appear โ€” callers never change. Java-style getters/setters on every field are noise. Validate at the boundary where bad data enters, and keep the rest plain.

Now practice

Property DrillsMake invalid states impossible with @property.2 challenges ยท ยท ~25 min