Python Properties Examples
Short, runnable programs that show python @property: getters and setters in action. Read the explanation, press Run, then change the code and try your own ideas. New to the topic? Start with the Python @property: Getters and Setters lesson.
1A computed attribute that is always up to date
duration is not stored. It is added up from the songs every time you read it, so it is correct after each add() call and can never drift out of sync.
class Playlist:
def __init__(self, name):
self.name = name
self.songs = [] # list of (title, seconds)
def add(self, title, seconds):
self.songs.append((title, seconds))
@property
def duration(self):
total = sum(seconds for _, seconds in self.songs)
return f"{total // 60}:{total % 60:02d}"
mix = Playlist("Focus")
mix.add("Intro", 95)
print(mix.duration)
mix.add("Deep Work", 250)
print(mix.duration)Expected output1:35
5:45
2A setter with clear error messages
The setter can reject a wrong type (TypeError) and a wrong value (ValueError) with different messages. The loop shows that a refused value leaves the old price in place.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if not isinstance(value, (int, float)):
raise TypeError("price must be a number")
if value < 0:
raise ValueError("price cannot be negative")
self._price = value
item = Product("Lamp", 40)
for new_price in [35, -5, "free"]:
try:
item.price = new_price
print("Price is now", item.price)
except (ValueError, TypeError) as err:
print(type(err).__name__ + ":", err)
print("Final price:", item.price)Expected outputPrice is now 35
ValueError: price cannot be negative
TypeError: price must be a number
Final price: 35
3A setter that cleans the data
A setter can also fix up the value before storing it. Here every username is trimmed and lower-cased, and an empty one is refused, so the rest of the program can rely on tidy data.
class Account:
def __init__(self, username):
self.username = username
@property
def username(self):
return self._username
@username.setter
def username(self, value):
cleaned = value.strip().lower()
if not cleaned:
raise ValueError("username cannot be empty")
self._username = cleaned
user = Account(" PixelFan ")
print(repr(user.username))
user.username = "ASHA"
print(user.username)
try:
user.username = " "
except ValueError as err:
print("Error:", err)Expected output'pixelfan'
asha
Error: username cannot be empty
4Compute once with cached_property
functools.cached_property runs the method the first time and keeps the answer on the object. The counter proves it ran once. If the data changes, del r.average forgets the cached value so the next read recalculates.
from functools import cached_property
class Report:
def __init__(self, numbers):
self.numbers = numbers
self.calculations = 0
@cached_property
def average(self):
self.calculations += 1
return sum(self.numbers) / len(self.numbers)
r = Report([80, 90, 100])
print(r.average, r.average, r.average)
print("Calculated", r.calculations, "time(s)")
r.numbers.append(60)
del r.average
print(r.average, r.calculations)Expected output90.0 90.0 90.0
Calculated 1 time(s)
82.5 2
5Read-only properties protect values
An order number should never change after creation. With only a getter, any attempt to assign raises AttributeError, and the value stays safe.
class Order:
def __init__(self, order_id):
self._order_id = order_id
@property
def order_id(self):
return self._order_id
order = Order(1042)
print(order.order_id)
try:
order.order_id = 7
except AttributeError as err:
print("Blocked:", err)
print(order.order_id)Expected output1042
Blocked: property 'order_id' of 'Order' object has no setter
1042
Practise next
Python @property: Getters and Setters exercises → Back to the lesson
Python Class Attributes vs Instance Attributes examplesPython Encapsulation: Public, Protected and Private examplesPython Dunder (Magic) Methods examples