Accessors and mutators in Python

The concept of object-oriented programming is related to the concept of encapsulation, i.e. hiding class fields and making only public methods (public API) available to read or change the values ​​of these fields. In Java, for example, it is solved at the language level using the private access modifier.

Python does not support such encapsulation. Using private variables like: _variable is just a matter of convention.

Consider the following example where we create a class to represent an employee:

class Employee:
	def __init__(self, name, salary, phone):
	    self.name = name
	    self.salary = salary
	    self.phone = phone

In Java, you should declare the name, salary, and phone variables private and refer to them via the getters and setters . In Python, it is not recommended to write accessor whose sole purpose is to return an attribute value or mutator to set an attribute value. Instead, you can refer to these fields directly. This has many advantages, but the advantages of encapsulating e.g.

johnDoe = Employee('John Doe', 8000, '555 111 22 33')
johnDoe.salary = 9000
print(johnDoe.salary)

The use of direct access to class attributes is a problem when it is necessary to make changes, e.g. introducing correctness control of the entered data.

Based on the code of the previously created Employee class, let’s assume that we would like to validate the entered telephone number, i.e. whether it has the appropriate number of digits, and at the same time remove unnecessary characters that are not digits.

To do this, we don’t need to change the way we communicate with the phone variable. We can still refer directly to the variable name. This is possible thanks to the @property decorator.

class Employee:

    def __init__(self, name, salary, phone):
        self.name = name
        self.salary = salary
        self.phone = phone
    @property
        def phone(self):
           return self._phone
    @phone.setter
        def phone(self, value):
            phone = ''.join(filter(lambda x: x.isdigit(), value))
            if len(phone) != 10:
                raise ValueError('Wrong phone number!')
            self._phone = phone

Calling the class’s constructor sets individual class attributes, while assigning the phone argument to the self.phone attribute causes the mutator to be called and thus validating the entered phone number at the time of creating the Employee class object.

Similarly, assigning a new value to the phone attribute will call the appropriate validation method, i.e.

johnDoe = Employee('John Doe', 8000, "555 111 22 33")
johnDoe.phone = '000' # raises ValueError - incorrect number length

Leave a Reply

Your email address will not be published. Required fields are marked *