In Python, properties provide a powerful way to manage the access and modification of class attributes. They allow for customized access control, making the class interface cleaner and more intuitive. By using properties, you can encapsulate data, adding validation logic without changing the class interface. Properties are defined using the @property
decorator, and can include getter, setter, and deleter methods.
Properties are a special kind of attribute in Python that enables you to add logic to attribute access. They allow for the definition of methods that control getting, setting, and deleting an attribute’s value, but use attribute access syntax rather than method calls. This makes the code that uses the class more readable and maintainable.
Properties are typically defined in three parts:
These methods are decorated with @property
, @<property name>.setter
, and @<property name>.deleter
, respectively.
Example:
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("Name must be a string")
self._name = value
@name.deleter
def name(self):
del self._name
# Usage
p = Person("Alice")
print(p.name) # Output: Alice
p.name = "Bob"
print(p.name) # Output: Bob
try:
p.name = 42 # Raises ValueError: Name must be a string
except ValueError as e:
print(e)
del p.name
In this example, name
is a property with getter, setter, and deleter methods. The setter method includes validation to ensure the name is always a string.
Let’s consider a more detailed example that demonstrates the use of properties with all three methods: getter, setter, and deleter.
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
@property
def width(self):
return self._width
@width.setter
def width(self, value):
if value <= 0:
raise ValueError("Width must be positive")
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self, value):
if value <= 0:
raise ValueError("Height must be positive")
self._height = value
@property
def area(self):
return self._width * self._height
@property
def perimeter(self):
return 2 * (self._width + self._height)
@width.deleter
def width(self):
print("Deleting width")
del self._width
@height.deleter
def height(self):
print("Deleting height")
del self._height
# Usage
rect = Rectangle(3, 4)
print(rect.width) # Output: 3
print(rect.height) # Output: 4
print(rect.area) # Output: 12
print(rect.perimeter) # Output: 14
rect.width = 5 # Update width
print(rect.area) # Output: 20
try:
rect.height = -1 # Raises ValueError: Height must be positive
except ValueError as e:
print(e)
del rect.width # Deleting width
try:
print(rect.width) # Raises AttributeError
except AttributeError as e:
print(e)
In this example, the Rectangle
class uses properties to control access to its width
and height
attributes, ensuring they are always positive values. Additionally, area
and perimeter
are defined as read-only properties, calculated based on the current dimensions of the rectangle.
Properties in Python provide a way to add logic to attribute access and modification, enabling encapsulation, validation, and computed attributes. By using the @property
decorator along with optional setter and deleter methods, you can create robust and maintainable class interfaces while keeping the internal representation of data hidden.