20.11. Public and Private Instance Variables

When we define a Python class, any instance’s instance variables can be accessed within or outside of the class. For example, suppose we have a class named Person that represents a person and if they are a “child” (for our purposes, anyone under 18 years old is considered a child):

Now, suppose we hand our Person class off to another programmer (maybe you are working as part of a team or you are writing a library for other people to use). They should not need to know exactly how you implemented your class; they should just be able to call the methods you have defined (getGivenName, getFamilyName, and isChild) and get the correct results. Ideally, you should be able to change the implementation of your Person class without breaking any code that uses it. For example, you might decide to change the names of the instance variables or change how instances store and represent information (like storing given and family names separately). As long as the methods you have defined still work, these changes should not make the other programmer change their code. This idea is called abstraction.

However, there’s a problem. The other programmer can also access Person’s instance variables from outside of the class definition, by writing p1.name and p1.age, if p1 is our instance. If they do, then they are relying on the implementation details of our class. If we change the implementation, then their code will break. For example, suppose we change the name of the age instance variable to howOld. Then their code that refers to .age will break. Further, if the other programmer’s code makes changes to the instance variables, then they might break our code. For example, if they change p1.age to be a string instead of an integer, then our isChild method will break.

These problems get more severe with larger and more complex classes. For these reasons, it is a good idea to hide the implementation details of our class from other programmers.

One way to hide implementation details is to make our instance variables private, which signals to other programmers that they should not access them directly. Unlike some other programming languages, Python does not “enforce” the idea of private instance variables, meaning that it is technically always possible for other programmers to reference and modify any instance variables. However, we can use naming conventions that (1) send a signal to other programmers that they should not access the instance variable directly and (2) make it harder for other programmers to access the instance variable directly.

Single underscores: the first way to do this is to start an instance variable name with a single underscore (_). In the case of Person, we would rename our instance variables to be _name and _age. This signals to other programmers that they should not access the instance variables directly. However, it is still possible for them to do so. For example, they could write p1._age to access the _age instance variable. This is something they should realize is not a good idea, but it is still possible.

Double underscores: The second way to do this is to start any instance variables with a double underscore (__). In the case of Person, we would rename our instance variables to be __name and __age. As is the case with a single underscore, this is a signal to other programmers that they should not access the instance variables directly. Further, Python “mangles” any instance variables that start with two underscores to make them more difficult (but not impossible) to access. Python mangles these names by adding the name of the class to the beginning of the instance variable name (_classname__variablename). For example, __age becomes _Person__age. Again, it is still possible for other programmers to do something they shouldn’t, by accessing .__Person_age, but they have to work harder to figure out what it’s called, and that may deter them.

For example, the following code throws an error when we try to access p1.__age:

In the code above, we have made the __name and __age instance variables private. We can still access them within the class definition using self.__name and self.__age, but we cannot access them directly outside of the class definition. Outside of the class definition, if we try to access p1.__age, we get an AttributeError. However, we can still access p1._Person__age.

You have attempted of activities on this page