Python > Object-Oriented Programming (OOP) in Python > Encapsulation > Properties (`@property`, `@setter`, `@deleter`)
Encapsulation with Properties: Managing Temperature
This snippet demonstrates encapsulation using properties in Python. It creates a Temperature
class where the temperature is stored internally in Celsius but can be accessed and set in Fahrenheit using properties. It showcases how to use @property
, @setter
, and @deleter
decorators to control attribute access and modification, ensuring data integrity and providing a cleaner interface.
Code Example
This code defines a Temperature
class. The _celsius
attribute is considered 'private' (indicated by the underscore), although Python doesn't enforce true privacy. The fahrenheit
and celsius
attributes are exposed as properties using the @property
decorator. The @fahrenheit.setter
and @celsius.setter
decorators define how the Fahrenheit and Celsius values can be set, performing the necessary conversion. A validation is applied in the Celsius setter to avoid setting temperature below absolute zero. The @fahrenheit.deleter
shows that you can intercept delete operations, useful to prevent accidental deletion or to perform custom cleanup actions.
class Temperature:
def __init__(self, celsius=0):
self._celsius = celsius
@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32
@fahrenheit.setter
def fahrenheit(self, value):
self._celsius = (value - 32) * 5/9
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._celsius = value
@fahrenheit.deleter
def fahrenheit(self):
print("Deleting Fahrenheit attribute is not allowed.")
# Example Usage
temp = Temperature(25)
print(f"Celsius: {temp.celsius}")
print(f"Fahrenheit: {temp.fahrenheit}")
temp.fahrenheit = 68
print(f"Celsius: {temp.celsius}")
try:
temp.celsius = -300
except ValueError as e:
print(e)
del temp.fahrenheit # Attempt to delete fahrenheit
Concepts Behind the Snippet
This snippet showcases encapsulation, a key principle of OOP. Encapsulation involves bundling data (attributes) and methods that operate on that data within a class, and restricting direct access to some of the object's components. Properties in Python provide a way to control access to attributes, allowing you to add logic (like validation or conversion) when getting, setting, or deleting an attribute. It hides the internal implementation details from the outside world, which can be changed later without affecting the code that uses the class (abstraction). Using the underscore prefix for the _celsius
attribute is a Python convention indicating that it's intended for internal use and shouldn't be directly accessed or modified from outside the class. Properties enhance encapsulation by providing a controlled interface for attribute access and modification. Properties provide better control and allow for validations to be applied to the value, like avoiding setting a temperature below absolute zero.
Real-Life Use Case
Consider a system for managing user profiles. You might want to store a user's age internally but expose it as 'date of birth'. Using properties, you can calculate the age from the date of birth whenever the 'age' property is accessed, and you can update the date of birth when the 'age' property is set. Another example: handling sensitive data like passwords. You can store a hashed password internally but expose a 'password' property. The setter can handle the hashing process before storing the password, improving security.
Best Practices
_attribute
). This is a convention, not a strict rule.
Interview Tip
Be prepared to explain the difference between direct attribute access and using properties. Understand how @property
, @setter
, and @deleter
work. Also, be ready to discuss why you would choose to use properties over simple attributes (e.g., for validation, conversion, or controlled access).
When to Use Them
Memory Footprint
Properties themselves introduce a minimal overhead in terms of memory. They are essentially function calls. The main memory usage comes from the attributes they manage. In the `Temperature` example, the `_celsius` attribute stores the temperature value.
Alternatives
get_fahrenheit()
and set_fahrenheit()
). This is a more verbose approach but can be useful in languages that don't have built-in property support.
Pros
Cons
FAQ
-
Why use a leading underscore for the `_celsius` attribute?
The leading underscore is a Python convention indicating that the attribute is intended for internal use and shouldn't be directly accessed or modified from outside the class. It's a signal to other developers that they should treat it as a 'private' attribute, even though Python doesn't enforce true privacy. -
What happens if I try to access `temp._celsius` directly?
You can access `temp._celsius` directly. Python does not prevent you from doing so. However, it's considered bad practice because it bypasses the encapsulation provided by the properties and could lead to unexpected behavior if the internal representation changes. -
Can I use properties with static attributes?
Yes, you can use properties with static attributes (class-level attributes). You would define the property methods within the class itself, and they would operate on the class-level attribute.