SyntaxStudy
Sign Up
Python Properties & Decorators
Python Intermediate 10 min read

Properties & Decorators

Properties & Decorators

Properties let you add getter/setter/deleter logic to attributes while keeping a clean attribute-style interface. Decorators modify function behavior.

@property

class Circle:
    def __init__(self, radius):
        self._radius = radius   # private convention

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

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Radius must be positive")
        self._radius = value

    @property
    def area(self):
        import math
        return math.pi * self._radius ** 2

c = Circle(5)
print(c.radius)   # 5
c.radius = 10     # calls setter
print(c.area)     # 314.159...
# c.radius = -1   # raises ValueError

Writing Decorators

import time, functools

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f"{func.__name__} ran in {end-start:.4f}s")
        return result
    return wrapper

@timer
def slow_sum(n):
    return sum(range(n))

slow_sum(1_000_000)
Example
class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Below absolute zero!")
        self._celsius = value

    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32

    @property
    def kelvin(self):
        return self._celsius + 273.15

t = Temperature(100)
print(f"{t.celsius}°C = {t.fahrenheit}°F = {t.kelvin}K")
Pro Tip

@property is great for computed attributes (like area or fahrenheit) — they look like plain attributes but run code when accessed.