Mastering Private and Protected Fields in Python Classes: A Complete Tutorial (44/100 Days of Python)
Python supports encapsulation, inheritance, and polymorphism. One of the ways that Python implements encapsulation is through the use of access modifiers for class attributes and methods. In this tutorial, we will discuss the concept of private and protected attributes and methods in classes in Python.
Private and protected fields in object-oriented programming are important concepts that help to ensure the encapsulation and maintain the integrity of a class. Encapsulation is the idea of hiding the internal details of an object and exposing only the necessary information to the outside world. This allows the class to be used in a predictable and consistent manner, even if the underlying implementation changes. By using private and protected fields, developers can control the visibility and accessibility of class attributes and methods, preventing accidental or intentional misuse. This helps to create a stable and robust codebase that is easier to maintain and less prone to bugs.
One example where hiding internal details might be useful is when creating a class to represent a complex mathematical function. Consider a class that represents a polynomial function, for example. The class could have private fields for the coefficients of the polynomial and public methods for evaluating the function at a specific point, finding the derivative, or plotting the function. By hiding the internal representation of the polynomial as private fields, the user of the class only needs to know how to call the public methods and doesn’t need to know the details of how the polynomial is stored and manipulated internally. This makes the class easier to use and less prone to bugs, as the user can’t accidentally modify the internal representation of the polynomial in a way that would cause unexpected results.
Private Attributes in Python Classes
In Python, private attributes are denoted by a double underscore prefix before the attribute name (e.g. __private_attribute
). The idea behind private attributes is that they can only be accessed within the class and should not be accessed from outside the class. However, it is important to note that the double underscore syntax is just a convention and not a strict rule.
When an attribute with a double underscore prefix is referenced from outside the class, the attribute name is automatically mangled to prevent accidental access. The mangled name is constructed by adding a prefix of “_ClassName” to the original name (e.g. _ClassName__private_attribute
):
class Person:
def __init__(self, name, age):
self.__private_attribute = 'This is a private attribute.'
self.name = name
self.age = age
person = Person('John Doe', 30)
print(person.__private_attribute) # AttributeError: 'Person' object has no attribute '__private_attribute'
As you can see, attempting to access the private attribute from outside the class results in an AttributeError
.
One way to access it, if that’s necessary, is to create a method (a class function) that would return the value of the __private_attribute
:
class Person:
def __init__(self, name, age):
self.__private_attribute = age
self.name = name
def get_private_attribute(self):
return self.__private_attribute
person = Person('John Doe', 30)
print(person.get_private_attribute()) # 30
print(person.__private_attribute) # AttributeError: 'Person' object has no attribute '__private_attribute'
In this example, the Person
class has a private attribute __private_attribute
that holds the person's age. The class has a public method get_private_attribute
that returns the value of the private attribute. When trying to access the private attribute directly from outside the class, an AttributeError
is raised, indicating that the attribute is not accessible. This protects the private attribute from being accidentally or intentionally modified from outside the class, maintaining the integrity of the class.
Protected Attributes in Python Classes
Protected attributes in Python are denoted by a single underscore prefix before the attribute name (e.g. _protected_attribute
). The idea behind protected attributes is similar to private attributes, in that they should not be accessed directly from outside the class. However, unlike private attributes, protected attributes can be accessed from within subclasses:
class Person:
def __init__(self, name, age):
self._protected_attribute = 'This is a protected attribute.'
self.name = name
self.age = age
class Employee(Person):
def display_protected_attribute(self):
print(self._protected_attribute)
employee = Employee('Jane Doe', 25)
employee.display_protected_attribute() # This is a protected attribute.
print(employee._protected_attribute) # This is a protected attribute.
In this example, the Employee
class inherits from the Person
class and is able to access the protected attribute through the display_protected_attribute
method. We will talk about inheritance in more detail later. Note here that employee._protected_attribute
actually prints the value stored in it. Yet, Python will warn you that you’re using a protected attribute which you shouldn’t.
Private Methods in Classes
Just like private attributes, private methods in Python are denoted by a double underscore prefix before the method name (e.g. __private_method
). Private methods are meant to be used only within the class and should not be accessed from outside the class:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __private_method(self):
print('This is a private method.')
person = Person('John Doe', 30)
person.__private_method() # AttributeError: 'Person' object has no attribute '__private_method'
Just like private attributes, attempting to access private methods from outside the class results in an AttributeError
.
Protected Methods in Classes
Protected methods in Python are denoted by a single underscore prefix before the method name (e.g. _protected_method
). Protected methods are meant to be used within the class and within subclasses, but not from outside the class:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def _protected_method(self):
print('This is a protected method.')
class Employee(Person):
def display_protected_method(self):
self._protected_method()
employee = Employee('Jane Doe', 25)
employee.display_protected_method() # This is a protected method.
employee._protected_method() # This is a protected method.
In this example, the Employee
class inherits from the Person
class and is able to access the protected method through the display_protected_method
method. Just like with protected attributes, you can still access the protected methods, yet Python will try to warn you that it’s not a good idea to access them outside of the class.
What’s next?
- If you found this story valuable, please consider clapping multiple times (this really helps a lot!)
- Hands-on Practice: Free Python Course
- Full series: 100 Days of Python
- Previous topic: Python Classes and Objects
- Next topic: What are Magic Methods in Python Classes?