This is an archived version of the course. Please see the latest version of the course.

Encapsulation the Pythonic way

So, in the previous page, we identified two problems:

  1. Getter and setter methods make our code less readable
  2. Users of the original Person class will need to modify their code.

Let us now try to tackle the same problem, but with a more Pythonic solution.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @property
    def age(self):
        return self.__age - 2

    @age.setter
    def age(self, new_age):
        if new_age < 30:
            self.__age = new_age
        else:
            print("Never! I am always under 30!")


person = Person("Josiah Wang", 20)  
print(person.age)
person.age = 10
print(person.age)
person.age = 70
print(person.age)
print(person.__age)  ## this won't work!

Now, lines 18-23 are much more readable than our previous solution! Users will also not have to change anything. We have managed to keep our interface, but at the same time have better control of our attributes.

In line 6, we introduced a @property decorator. Without going into too much detail, this decorator converts the method age() in line 7 to become a public, readable property age. The age() method in line 7 will be invoked when you try to read the age property, for example in line 19.

Similarly, in line 10, the @property_name.setter decorator turns the age() method in line 11 to become a public, writable property age. So the method in line 11 will be invoked when a user tries to write to the property, for example in lines 20 and 22. In fact, I also used this in the constructor in line 4!

If we were to remove lines 10-15, then age will be a read-only property.

Decorators are an advanced Python topic, so we will not be discussing them in this tutorial. If you are really interested, I go in depth into decorators in my Python Programming module.

So, in summary, keep your attributes in Python public. And when you need more control, encapsulate the attributes by converting them to properties.