property()
property(fget=None, fset=None, fdel=None, doc=None) Returns:
property object · Updated March 13, 2026 · Built-in Functions built-in oop encapsulation getter setter
The property() function returns a property attribute that provides controlled access to class attributes. It lets you define getter, setter, and deleter methods for an attribute, enabling encapsulation without requiring the @property decorator. Properties implement Python’s descriptor protocol under the hood.
Syntax
property(fget=None, fset=None, fdel=None, doc=None)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
fget | callable | None | A function to get the attribute value. Called when the property is accessed. |
fset | callable | None | A function to set the attribute value. Called when assigning to the property. |
fdel | callable | None | A function to delete the attribute value. Called when del is used on the property. |
doc | str | None | The docstring for the property. If omitted, inherits from fget’s docstring if available. |
Examples
Read-only property
This example creates a property with only a getter, making the attribute read-only:
class Temperature:
def __init__(self):
self._celsius = 0
def get_celsius(self):
return self._celsius
celsius = property(get_celsius)
t = Temperature()
print(t.celsius)
# 0
# Assigning raises AttributeError since there is no setter
# t.celsius = 25
Full property with getter, setter, and deleter
This example shows all three methods in action:
class Person:
def __init__(self, name):
self._name = name
def get_name(self):
return self._name
def set_name(self, value):
if not value:
raise ValueError("Name cannot be empty")
self._name = value
def del_name(self):
print(f"Deleting {self._name}")
del self._name
name = property(get_name, set_name, del_name, "The person's name")
p = Person("Alice")
print(p.name)
# Alice
p.name = "Bob"
print(p.name)
# Bob
del p.name
# Deleting Bob
Note that accessing p.name after deletion raises an AttributeError because the underlying _name attribute no longer exists.
Computed property
Properties can compute values on the fly:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def get_area(self):
return self.width * self.height
area = property(get_area)
r = Rectangle(5, 3)
print(r.area)
# 15
Common Patterns
Validation in setters
Setters are useful for validating data before storing it:
class Account:
def __init__(self, balance):
self.balance = balance
def get_balance(self):
return self._balance
def set_balance(self, value):
if value < 0:
raise ValueError("Balance cannot be negative")
self._balance = value
balance = property(get_balance, set_balance)
account = Account(100)
account.balance = 50
print(account.balance)
# 50
account.balance = -10
# Traceback (most recent call last):
# ValueError: Balance cannot be negative
Lazy computation
A property can delay expensive computation until the value is actually needed:
class LazyLoader:
def __init__(self):
self._data = None
@property
def data(self):
if self._data is None:
print("Loading data...")
self._data = [1, 2, 3]
return self._data
loader = LazyLoader()
print("Created")
print(loader.data)
# Loading data...
# [1, 2, 3]
print(loader.data)
# [1, 2, 3]
See Also
- built-in::classmethod — decorator for class methods
- built-in::staticmethod — decorator for static methods
- Descriptors — the protocol that underlies property()