Introduction
The property decorator in Python is an invaluable tool for designing elegant, Pythonic classes. With @property, you can write attributes that act like normal instance attributes, but execute custom code when accessed. This opens up many possibilities! In this article, we’ll explore common uses for @property and unlock its full potential with examples.
How Python property Decorator Works
The @property decorator is applied to methods in a class definition. When you access a @property method on an instance, the method will be called and the return value accessed. Consider this example:
class Person:
def __init__(self, name):
self.name = name
@property
def name_length(self):
return len(self.name)
p = Person('Eric')
print(p.name) # 'Eric'
print(p.name_length) # 4
The name_length method is decorated with @property. When we access p.name_length, the method is called automatically and the return value used. But we don’t have to call it like a method – it looks like an attribute!
Benefits of Using @property
@property methods provide several advantages:
- Makes attributes readable and writable
- Encapsulates validation logic on attribute access
- Allows computed attributes based on internal state
- Easy to add change notifications when attributes are modified
Next, we’ll go through examples of these benefits.
Turning Methods into Readable Attributes
A common use of @property is making attributes readable while restricting write access. Consider this class:
class Circle:
def __init__(self, radius):
self.radius = radius
def get_area(self):
return 3.14 * (self.radius ** 2)
c = Circle(5)
print(c.get_area())
To find the area, we have to explicitly call get_area() like a method. With @property, we can streamline this:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14 * (self.radius ** 2)
c = Circle(5)
print(c.area)
Now area can be accessed like an attribute for a cleaner syntax!
Encapsulating Validation Logic
A common need is validating values before assignment. With @property, we can encapsulate this logic neatly:
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 must be positive')
self._radius = value
Now setting radius will automatically run validation. Properties make encapsulation easy!
Computed Attributes
Since @property methods are just methods, we can use them to compute values on demand based on the internal state.
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
return self.first_name + ' ' + self.last_name
p = Person('Eric', 'Idle')
print(p.full_name) # 'Eric Idle'
full_name is computed on the fly based on first_name and last_name. No need to store redundancies!
Change Notifications
Here’s one last neat trick – we can trigger actions when attributes are modified by listening for attribute changes.
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
print('Getting name')
return self._name
@name.setter
def name(self, value):
print('Setting name to ' + value)
self._name = value
p = Person('Eric')
p.name = 'John'
This will print ‘Setting name to John’ when we assign to name. Powerful stuff!
Conclusion
The @property decorator enables rich object behaviors while providing a clean interface. By unlocking cool capabilities like change notifications and computed attributes, @property makes your classes versatile, reusable and Pythonic. So next time you’re designing a class, reach for @property to take things to the next level!
Frequently Asked Questions
Q: What happens if I only use @property without a setter?
A: The attribute will become read-only, since writes will be blocked. Attempts to assign to the property will raise an AttributeError.
Q: Can I use @property on classmethods or staticmethods?
A: Yes, the @property decorator works on any kind of method in a class definition.
Q: Does @property have any performance costs?
A: No, since the lookup happens on the class, not per instance, there is no performance penalty for using @property.
Q: Can I have multiple @property decorators on the same method?
A: No, only one @property decorator can be applied per method. However, you can stack other decorators like @classmethod before @property.
Q: What is a common use case for @property methods?
A: Validating attribute values before assignment is probably the most frequent use case for @property methods. This encapsulates the validation cleanly.