Properties in Python

Properties in Python

Introduction to Properties in Python

In Python, properties are attributes of a class that are accessed via methods but behave like regular attributes. Properties are usually defined using the @property, @setter, and @deleter decorators.

Adding Properties to a Child Class

Define a Property in a Parent Class

First, let’s define a parent class with properties.

Example: 

class Animal:
    def __init__(self, name, age):
        self._name = name
        self._age = age
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, value):
        self._name = value
    @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
  • The properties name and age are defined with getter and setter methods. The @property decorator is used to define a readable attribute, while @name.setter and @age.setter allow you to set values.

Add Properties in the Child Class

Next, we can add specific properties to a child class that inherits from the Animal class.

Example 

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self._breed = breed
    @property
    def breed(self):
        return self._breed
    @breed.setter
    def breed(self, value):
        self._breed = value
  • Dog inherits from Animal and adds a new property breed with its own getter and setter methods.

Using Properties in the Child Class

You can now create instances of the child class and use the properties as if they were regular attributes.

Example: 

my_dog = Dog("Rex", 5, "Labrador")
print(my_dog.name)   # Rex
print(my_dog.age)    # 5
print(my_dog.breed)  # Labrador
my_dog.name = "Max"
my_dog.age = 6
my_dog.breed = "Golden Retriever"
print(my_dog.name)   # Max
print(my_dog.age)    # 6
print(my_dog.breed)  # Golden Retriever
try:
    my_dog.age = -1
except ValueError as e:
    print(e)  # Age cannot be negative.
  • The properties defined in both the parent and child classes are used to access and modify the object’s attributes.

Properties with Dynamic Calculations

You can also define properties that perform dynamic calculations or depend on other attributes.

Example: 

class Circle:
    def __init__(self, radius):
        self._radius = radius
    @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):
        import math
        return math.pi * (self._radius ** 2)
  • The area property is computed dynamically based on the radius. It does not have a setter method because the area is directly related to the radius.

Usage: 

my_circle = Circle(5)
print(my_circle.radius)   # 5
print(my_circle.area)     # 78.53981633974483
my_circle.radius = 10
print(my_circle.area)     # 314.1592653589793

Redefining Properties in the Child Class

You can also redefine properties in a child class to adapt them to specific needs while retaining some inherited functionality.

Example: 

class Animal:
    def __init__(self, name, age):
        self._name = name
        self._age = age
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, value):
        self._name = value
    @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
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self._breed = breed
    @property
    def breed(self):
        return self._breed
    @breed.setter
    def breed(self, value):
        self._breed = value
    @property
    def age(self):
        return super().age
    @age.setter
    def age(self, value):
        if value > 20:
            raise ValueError("A dog's age cannot exceed 20 years.")
        super(Dog, type(self)).age.fset(self, value)
  • In this example, the age property is redefined in the Dog class to add specific validation for dogs, while still using the parent class’s age property functionality.

Using Properties in Real-World Contexts

Properties are often used in real-world scenarios to encapsulate specific behaviors related to data.

Example: 

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)

Usage: 

my_rectangle = Rectangle(4, 5)
print(my_rectangle.area)      # 20
print(my_rectangle.perimeter) # 18
my_rectangle.width = 6
print(my_rectangle.area)      # 30

Summary

  • Defining Properties: Use @property, @setter, and @deleter decorators to create properties with getter, setter, and deleter methods.
  • Adding Properties in a Child Class: You can add new properties or redefine inherited ones to meet the specific needs of the subclass.
  • Dynamic Properties: Properties can perform dynamic calculations based on other attributes.

Validation and Encapsulation: Properties help validate data and encapsulate logic related to accessing and modifying attributes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *