🏠 Python OOP — The @property Decorator

Introduction 🌟

The @property decorator in Python allows you to use methods like attributes. It helps you implement **getter**, **setter**, and **deleter** functionality in a clean and Pythonic way, while still protecting internal data.

Note

💡 @property = read-only attribute
💡 @attribute.setter = modify attribute
💡 @attribute.deleter = delete attribute

1. Basic Example of @property 🧱

basic_property.py

class Person:
    def __init__(self, name):
        self._name = name   # protected attribute

    @property
    def name(self):
        return self._name

p = Person("Sathish")
print(p.name)    # accessing method like an attribute

p.name calls name() internally
✔ No parentheses needed

2. Why Use @property? 🤔

  • ✔ Encapsulates (hides) internal data
  • ✔ Adds validation while still using attribute syntax
  • ✔ Makes code cleaner and more readable
  • ✔ Allows converting methods → attributes without breaking code

3. Adding a Setter Method ✏️

setter_example.py

class Person:
    def __init__(self, age):
        self._age = age

    @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(23)
p.age = 25       # setter called
print(p.age)

✔ Ensures age is always valid.

4. Adding a Deleter Method 🗑️

deleter_example.py

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.deleter
    def name(self):
        print("Deleting name...")
        del self._name

p = Person("Sathish")
del p.name

✔ Handles attribute deletion safely.

5. Real-World Example: Salary With Validation 💰

salary_example.py

class Employee:
    def __init__(self, salary):
        self._salary = salary

    @property
    def salary(self):
        return self._salary

    @salary.setter
    def salary(self, amount):
        if amount < 0:
            raise ValueError("Salary cannot be negative")
        self._salary = amount

e = Employee(30000)
e.salary = 35000
print(e.salary)

6. Computed Properties (No Stored Attribute) 🧮

computed_property.py

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    @property
    def area(self):
        return self.width * self.height

r = Rectangle(5, 10)
print(r.area)

✔ Useful when the value depends on calculation.

7. Property with Private (Protected) Attributes 🔐

private_property.py

class User:
    def __init__(self, username):
        self._username = username

    @property
    def username(self):
        return self._username

u = User("admin")
print(u.username)

Note

_username indicates “not to be accessed directly”.

8. Using @property to Prevent Breaking Changes 🧩

prevent_breaking.py

class Product:
    def __init__(self, price):
        self._price = price

    @property
    def price(self):
        return self._price   # previously a direct attribute

p = Product(500)
print(p.price)

✔ Useful when turning direct attributes into protected ones without changing external code.

9. Example: Temperature Class 🌡️

temperature.py

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Temperature cannot go below absolute zero!")
        self._celsius = value

    @property
    def fahrenheit(self):
        return (self._celsius * 9/5) + 32

t = Temperature(25)
print(t.fahrenheit)
t.celsius = -300  # raises error

10. Property vs Getter/Setter Methods (Old Style) ⚔️

old_style.py

# Old style
class Person:
    def get_name(self): ...
    def set_name(self, name): ...

# New style (Recommended)
class Person:
    @property
    def name(self): ...
Old Style@property Style
Java-likePythonic
More codeCleaner & simpler
Method-like callsAttribute-like access

11. Best Practices 💡

  • ✔ Always prefix internal variables with _
  • ✔ Use setters only when validation is required
  • ✔ Use @property to create read-only attributes
  • ✔ Avoid heavy logic inside property methods

Conclusion 🎉

>>“The @property decorator gives you powerful control over your object's data — with the beautiful simplicity of attribute access.” ✨

You now fully understand the Property Decorator in Python! Want the next topic? Try Encapsulation, Magic Methods, Inheritance, or Polymorphism. Just tell me! 😊