Getter and setter are used in many object-oriented programming languages, (click the link for knowing how it works in Java), however, python provides a much easier way to use getter and setter with its built-in @property decorator.

Wait, decorator? Sounds familiar, right? If you haven't heard of it before, or if you have heard of it but you are not sure what it does, maybe check this out: What is a Decorator in Python? Sweeter your Python code in an advanced way with the help of decorators.

Let's start with a normal class that we usually create and use.

class House:
    def __init__(self, owner, doorlock_password):
        self.owner = owner
        self.doorlock_password = doorlock_password
tinyhouse = House('Allie', '123456')
print(tinyhouse.owner)
print(tinyhouse.doorlock_password)
tinyhouse.doorlock_password = '87654'
print(tinyhouse.doorlock_password)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Allie
123456
87654

In this code, the password is easy to call, and at the same time, it is easy to change, which is not safe (whether it is the password of your entry door lock in reality or the design of the code).

Then you might set doorlock_password to a private value. However, this will prevent you from even calling it.

class House:
    def __init__(self, owner, doorlock_password):
        self.owner = owner
        self._doorlock_password = doorlock_password
tinyhouse = House('Allie', '123456')
print(tinyhouse.owner)
print(tinyhouse.doorlock_password)
>>>>>>>>>>>>>>>>>>>>>>>>>
Allie
Traceback (most recent call last):
  File "<string>", line 8, in <module>
AttributeError: 'House' object has no attribute 'doorlock_password'

So we decided to create a function to handle this situation, that is to say, the method of getting and setting will only be known by the developers of this program. Users who want to get or set a password must go through the developer.

class House:
    def __init__(self, owner, doorlock_password):
        self.owner = owner
        self._doorlock_password = doorlock_password
        
    def get_doorlock_password(self):
        return self._doorlock_password
        
    def set_doorlock_password(self, new_password):
        self._doorlock_password = new_password
        print('Password Changed')
        
        
tinyhouse = House('Allie', '123456')
result = tinyhouse.get_doorlock_password()
print(result)
tinyhouse.set_doorlock_password('54321')
result = tinyhouse.get_doorlock_password()
print(result)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
123456
Password Changed
54321

But this makes the code feel a bit complicated, right?

And it's time for @property!

The @property decorator

getter

We want the get value action just easy as begin, instead of calling a function. Let do this.

class House:
    def __init__(self, owner, doorlock_password):
        self.owner = owner
        self._doorlock_password = doorlock_password
        
    @property
    def password(self):
        return self._doorlock_password
     
    def set_doorlock_password(self, new_password):
        self._doorlock_password = new_password
        print('Password Changed')
        
        
tinyhouse = House('Allie', '123456')
print(tinyhouse.password)

By adding @property above the function password, it makes this function be converted as an attribute, so the users can still get the class private value through tinyhouse.password, instead of calling function tinyhouse.password().

setter

The part of how to read the private value is completed, so how to modify the private value?

class House:
    def __init__(self, owner, doorlock_password):
        self.owner = owner
        self.password = doorlock_password
        
    @property
    def password(self):
        return self._doorlock_password
    @password.setter
    def password(self, new_password):
        self._doorlock_password = new_password
        print('Password Changed')
        
        
tinyhouse = House('Allie', '123456')
print(tinyhouse.password)

In this case, when we create a new House class tinyhouse, instead of assigning the doorlock_passowrd value directly into initial (__init__), it calls the property password.setter function self.password= doorlock_password. Then the 123456 will be assigned to the private variable _doorlock_password by this function.

In addition, you can process the value or verify it before assigning it through this setter.

result:

Invalid Password. The length of password must be between 6 to 12.
Invalid Password. The length of password must be between 6 to 12.
Password Changed
123456678

deleter

Here is another property decorator called deleter, you could execute this by using del. In this example, I utilize deleter as a reset action for the password.

Password Changed
123456678
Password has been reset.
0000

Conclusion

In object-oriented programing, encapsulation is a basic and important concept as well as a component. We should not allow external users to directly edit or change the content of the object, but can only modify or access internal attributes through methods.

And @property could make a class's function become a read-only attribute, as well as allow a setter, getter, deleter method for the attribute.

For more information from different perspectives, here is a wonderful tutorial from Programiz that explains the property decorator as well.

You might also want to know about:

More content at plainenglish.io

Support my writing by becoming a Medium member today and getting access to an unlimited number of articles.