Chapter 3: Encapsulation

Encapsulation in inheritance

face Josiah Wang

When you are designing your class so that it can be subclassed, you should be aware that the non-public attributes will not be accessible by your subclass. For example, self.__name cannot be directly accessed by Hero (because it has been automatically renamed to _Character__name).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Character:
    def __init__(self, name):
        self.__name = name

    def greet(self):
        print(f"My name is {self.__name}")


class Hero(Character):
    def __init__(self, name):
        super().__init__(name)

    def shout(self):
        print(f"I AM {self.__name.upper()}")


hero = Hero("Iron Man")
hero.shout() # AttributeError: 'Hero' object has no attribute '_Hero__name'

Python’s recommendation is for you to prefix the attribute name with a single underscore instead. Technically, it will not ‘hide’ the attribute as before, but it hints to a programmer that the attribute should only be used by a subclass. Of course, this also means that anybody can access this attribute freely, but Python trusts that a programmer will do the right thing and not misuse the given freedom!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Character:
    def __init__(self, name):
        self._name = name

    def greet(self):
        print(f"My name is {self._name}")


class Hero(Character):
    def __init__(self, name):
        super().__init__(name)

    def shout(self):
        print(f"I AM {self._name.upper()}")


hero = Hero("Iron Man")
hero.shout() # I AM IRON MAN

If you have previously done OOP with Java or C++, you can think of this as marking the attribute as “protected” (without any strict enforcement).