Computed Attributes With @property
Sometimes a value should look like an attribute but actually be calculated on the fly, or be checked before it is allowed to change. The @property decorator turns a method into something you read with no parentheses, like a normal attribute.
A read-only computed value
class Rectangle:
def __init__(self, w, h):
self.w = w
self.h = h
@property
def area(self):
return self.w * self.h
r = Rectangle(3, 4)
print(r.area) # 12, note: no parenthesesBecause area is a property, you write r.area, not r.area(). It recalculates every time, so it stays correct even if w or h change.
Validating a value with a setter
You can also guard writes. Define the property, then a matching @<name>.setter. By convention the real data is stored in a private-looking attribute with a leading underscore.
class Person:
def __init__(self, age):
self.age = age # this goes through the setter below
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("age cannot be negative")
self._age = value
p = Person(30)
print(p.age) # 30
p.age = 31 # ok
# p.age = -5 # would raise ValueErrorFrom the outside it still looks like a plain attribute, but every read and write runs your code.
Define a class Circle whose __init__ takes radius and assigns it to self.radius (which goes through a setter). Add a radius property and a radius setter that raises ValueError when given a negative number, storing the value in self._radius. Add a read-only diameter property that returns radius * 2.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.