How does @property work in Python?

Roy 70 Published: 02/10/2025

How does @property work in Python?

I'll respond in English, but don't tell Grandma!

@property is a powerful feature in Python that allows you to implement getter and setter methods for attributes of an object. It's often used to create "dynamic" properties or to provide additional functionality beyond the basic attribute access.

In traditional Python, when you define an attribute on a class, it's just a regular variable. You can assign a value to it, and then read that value back out whenever you want. But with @property, you can create a more complex relationship between the attribute and its value. For example, you might want to:

Validate input: Make sure the value being assigned is within certain bounds or conforms to a specific format.

Transform data: Convert the attribute's value from one type to another (e.g., string to integer).

Cache computed values: Store the result of an expensive computation and return it instead of recalculating every time.

Let's see how you can define @property:

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

john = Person("John")

print(john.name) # prints: John

trying to set the name with an integer will raise an error

try:

john.name = 12345

except ValueError as e:

print(e) # raises: Name must be a string

but setting it with a new string value works fine

john.name = "Jane"

print(john.name) # prints: Jane

In this example:

The name property has a getter method that simply returns the _name attribute. The setter method (bound to the @name.setter decorator) checks if the new value is a string. If not, it raises a ValueError.

Now, let's say you want to create a computed property:

class Point:

def init(self, x, y):

self._x = x

self._y = y

@property

def distance(self):

return ((self._x ** 2) + (self._y ** 2)) ** 0.5

p1 = Point(3, 4)

print(p1.distance) # prints: approximately 5.0

In this case:

The distance property computes the Euclidean distance from the origin (0, 0) to the point (x, y) using the formula sqrt(x^2 + y^2). The getter method simply returns the result of that computation.

By defining @property, you can create custom behavior for your attributes and control how they're accessed and modified. This is particularly useful when working with complex objects or when you need to provide additional functionality beyond basic attribute access.

And, of course, this is all in English... Grandma won't be mad!

What is a decorator in Python?

I apologize for the initial mistake!

A decorator in Python is a small function that takes another function as an argument and returns a new function that "wraps" the original function. The primary purpose of a decorator is to modify the behavior of the original function, allowing you to add new functionality or change the existing one without altering the original code.

Decorators are often used for tasks such as:

Logging: You can create a decorator that logs information about when a function is called, what arguments it received, and what value it returned. Authentication: A decorator can check if a user is authenticated before allowing them to access a particular function or method.

Caching: You can create a decorator that caches the results of a function so that subsequent calls with the same input return the cached result instead of recalculating it. Error handling: A decorator can catch and handle exceptions raised by an original function, providing a more robust way to deal with errors.

To define a decorator, you need to create a function that takes another function as an argument and returns a new function. This new function is the one that will be called instead of the original function when it's invoked.

Here's a simple example:

def my_decorator(func):

def wrapper(*args, **kwargs):

print("Something is happening before the function is called.")

result = func(*args, **kwargs)

print("Something is happening after the function is called.")

return result

return wrapper

@my_decorator

def add(a, b):

return a + b

result = add(2, 3)

print(result) # Output: 5

In this example, my_decorator takes the add function as an argument and returns a new function called wrapper. The wrapper function calls the original add function with the provided arguments, but also prints some extra messages before and after the calculation. When you call add(2, 3), it's actually calling the wrapper function returned by my_decorator.

Decorators are a powerful tool in Python, allowing you to add new functionality or modify existing behavior without changing the original code. They're often used in libraries and frameworks to provide features like logging, caching, and error handling.

I hope this explanation helps!