0
0
PythonHow-ToBeginner · 3 min read

How Property Works Internally in Python: Explained Simply

In Python, property works internally using the descriptor protocol, which means it defines methods like __get__, __set__, and __delete__ to control attribute access. When you use @property, Python creates a property object that manages getting, setting, and deleting values behind the scenes.
📐

Syntax

The property function creates a managed attribute by defining methods for getting, setting, and deleting its value.

Its basic syntax is:

  • property(fget=None, fset=None, fdel=None, doc=None)

Where:

  • fget: function to get the attribute value
  • fset: function to set the attribute value
  • fdel: function to delete the attribute value
  • doc: optional documentation string

Using @property decorates a method as the getter, and you can define setter and deleter with @attribute.setter and @attribute.deleter.

python
class MyClass:
    def __init__(self):
        self._x = None

    def get_x(self):
        return self._x

    def set_x(self, value):
        self._x = value

    def del_x(self):
        del self._x

    x = property(get_x, set_x, del_x, "I'm the 'x' property.")
💻

Example

This example shows how property controls access to a private attribute _temperature. The getter returns the value, the setter validates it, and the deleter removes it.

python
class Temperature:
    def __init__(self, temp=0):
        self._temperature = temp

    @property
    def temperature(self):
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature can't be below absolute zero!")
        self._temperature = value

    @temperature.deleter
    def temperature(self):
        print("Deleting temperature...")
        del self._temperature

# Usage
temp = Temperature(25)
print(temp.temperature)  # Calls getter

try:
    temp.temperature = -300  # Calls setter, raises error
except ValueError as e:
    print(e)

temp.temperature = 100  # Valid set
print(temp.temperature)

del temp.temperature  # Calls deleter
Output
25 Temperature can't be below absolute zero! 100 Deleting temperature...
⚠️

Common Pitfalls

Common mistakes when using property include:

  • Not using a private attribute (like _x) inside getter/setter, causing infinite recursion.
  • Forgetting to define a setter when you want to assign values, leading to AttributeError.
  • Misusing the decorator syntax, such as defining setter without the matching property name.

Here is an example of a common mistake and the correct way:

python
class Wrong:
    def __init__(self):
        self.x = 0

    @property
    def x(self):
        return self.x  # Wrong: calls itself recursively

class Right:
    def __init__(self):
        self._x = 0

    @property
    def x(self):
        return self._x  # Correct: accesses private attribute

    @x.setter
    def x(self, value):
        self._x = value
📊

Quick Reference

Summary tips for using property:

  • Use a private attribute (like _attr) to store data internally.
  • Define a getter method with @property to access the value.
  • Define a setter method with @property_name.setter to set the value safely.
  • Optionally, define a deleter with @property_name.deleter to clean up.
  • Remember, property uses the descriptor protocol internally to manage attribute access.

Key Takeaways

Python's property uses the descriptor protocol with __get__, __set__, and __delete__ methods internally.
Use @property to define a getter and @property_name.setter to define a setter for controlled attribute access.
Always store the actual data in a private attribute to avoid infinite recursion.
Defining a setter is necessary if you want to assign values to a property; otherwise, it is read-only.
Property helps encapsulate attribute access, allowing validation and control without changing the interface.