PythonMastery

Property decorator in Python

Use @property to check a value when it is set (a radius cannot be negative) and to compute a value, such as an area, every time it is read.

@property lets a method look like a normal attribute. You read c.area without brackets, and Python runs a method to get the value. With a setter, you can also run code when someone assigns a new value, for example to reject a wrong one.

The program

python
import math


class Circle:
    def __init__(self, radius):
        self.radius = radius  # goes through the setter below

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

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

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


c = Circle(5)
print(f"radius {c.radius}, area {c.area:.2f}")

c.radius = 10
print(f"radius {c.radius}, area {c.area:.2f}")

try:
    c.radius = -3
except ValueError as e:
    print("Error:", e)
print("radius is still", c.radius)
output
radius 5, area 78.54
radius 10, area 314.16
Error: radius cannot be negative
radius is still 10

How it works

Read-only attributes

Assigning to a property that has no setter raises AttributeError:

python
import math

class Circle:
    def __init__(self, radius):
        self.radius = radius

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

c = Circle(2)
try:
    c.area = 100
except AttributeError as e:
    print("Error:", e)
output
Error: property 'area' of 'Circle' object has no setter

Learn the idea: Object-Oriented Programming, Decorators: Functions That Wrap Functions