Setter decorator
Object-oriented programming helps us to protect the attributes of our class from unwanted modifications. This follows the principle of encapsulation. Just as the engine of a car is hidden from the outside to protect it, Python allows us to protect the attributes of our classes.
Imagine that you want to protect the age
attribute so that a negative value cannot be used. One way to do this is to check the age
in the constructor.
class Person:
def __init__(self, first_name, last_name, age):
if age < 0:
raise Exception("Age cannot be negative.")
self.first_name = first_name
self.last_name = last_name
self.age = age
This protects against the following:
p = Person("Ana", "Ruiz", -1)
# Exception: Age cannot be negative.
However, we are not protected from the following. We build the object with a valid age, but then modify it.
p = Person("Ana", "Ruiz", 20)
p.age = -1
print(p.age) # -1
To solve this, we can use the following decorators, which go hand in hand:
age.setter
: Allows adding logic to be executed when the attribute is modified, in this caseage
.property
: Allows access to an attribute. We will see it in detail later.
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age < 0:
raise ValueError("Age cannot be negative.")
self.__age = age
Some notes:
- By using the
__
in__age
, we tell Python that we want to hide this attribute from the outside. It is like saying we do not want anyone to modify it. It is internal to the class. - With
@age.setter
, we tell Python that anyone who wants to modifyage
must do it through this method. And this method has some logic. We forbid the age to be negative.
As you can see, we are now protected from a negative age.
p = Person("Ana", "Ruiz", 20)
p.age = -1
# ValueError: Age cannot be negative.
This is an example of the famous encapsulation of object-oriented programming. It encapsulates the attributes by isolating them from the outside world and can only be modified by certain functions, which are responsible for verifying that everything is correct.
An important note is that Python allows you to do everything. If you really try and want to skip the verification, you can set a negative age using _Person__age
. But this is a bit more advanced and a field you should not access.
p = Person("Ana", "Ruiz", 20)
p._Person__age = -1
print(p.age) # -1