@property — Computed Attributes

Expose methods as attributes, add validation, and keep a clean public API without breaking callers.

Coming from other languages you might reach for get_price() and set_price(). Python's answer is the @property decorator: it lets a method be accessed like a plain attribute, so callers write obj.price while you keep full control behind the scenes.

The pattern

class Circle:
    def __init__(self, radius):
        self.radius = radius
    @property
    def area(self):                 # accessed as circle.area, no ()
        return 3.14159 * self.radius ** 2

c = Circle(10)
print(c.area)      # 314.159 — looks like an attribute, runs like a method

Validation with a setter

Add a matching @name.setter to guard assignment. This is the key benefit: you can start with a plain attribute, and later wrap it in a property to add validation without changing a single line of calling code.

Read-only by design

A property with a getter but no setter is read-only — assigning to it raises AttributeError. That is exactly how you expose a derived value that should never be set directly.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A User model exposes 'password' as a write-only property that automatically hashes on assignment.
  • A lazy-loading class computes a 'data' property on first access and caches the result for subsequent calls.
  • A geometric class exposes 'diameter' and 'radius' as paired properties that stay in sync.

More examples

Getter and setter with validation

Uses a setter to validate that a percentage stays within 0-100 before storing it.

Example · python
class Percentage:
    @property
    def value(self): return self._value

    @value.setter
    def value(self, v):
        if not 0 <= v <= 100:
            raise ValueError(f'{v} is not 0-100')
        self._value = v

p = Percentage()
p.value = 75
print(p.value)   # 75

Deleter method

Implements a @data.deleter to allow 'del obj.data' to clear a cached value.

Example · python
class CachedData:
    def __init__(self): self._cache = None

    @property
    def data(self):
        if self._cache is None:
            self._cache = 'expensive result'
        return self._cache

    @data.deleter
    def data(self):
        self._cache = None
        print('Cache cleared')

cd = CachedData()
print(cd.data)   # expensive result
del cd.data      # Cache cleared

Paired computed properties

Exposes both radius and diameter as properties that derive from the same internal value.

Example · python
class Circle:
    def __init__(self, radius): self._r = radius

    @property
    def radius(self): return self._r

    @property
    def diameter(self): return self._r * 2

    @diameter.setter
    def diameter(self, d): self._r = d / 2

c = Circle(5)
print(c.diameter)   # 10
c.diameter = 14
print(c.radius)     # 7.0

Discussion

  • Be the first to comment on this lesson.