Table of Contents
Have you ever used data structures like pandas dataframe while programming in python? Don’t they make working with complex tabular data a cakewalk? You can just use methods provided in the pandas module and every task is executed. Have you ever thought about how these complex data structures are handled by python? You didn’t! Because you didn’t need that. We don’t need to know and we are not allowed to know what happens behind when we execute those methods. Private methods in Python are often used to implement those operations that a normal user doesn’t need to know the details about. In this article, we will discuss what private methods in python are, how we can use them, and how we can access a private method in python.
What is a private method in Python?
Private methods are such methods that cannot be accessed outside a class definition. In the real world, if something is private to us, other people aren’t supposed to have access to that. Similarly, We are not supposed to access the private methods defined inside a class.
Python doesn’t support private methods. But, we can simulate the implementation of private methods in python. For that, we have to define the name of the private method using two underscore signs as follows.
1 2 3 4 5 |
def __methodName(): pass |
Here, we have used the def
keyword to define the method and the pass
keyword has been used to create a method body that does nothing.
Why do we need a private method in Python?
Private methods are used for various purposes by programmers. Let us understand using an example.
For instance, let us create a class named Student
to keep the marks of students. Here, we can keep the marks of all subjects using a python dictionary as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology |
Now, suppose that we create two methods namely strongerSubjects
and weakerSubjects
. The strongerSubjects
method to get the name of those subjects in which the students have scored higher than their average marks and the weakerSubjects
method to get the name of those subjects in which they have scored less than their average marks. We can do it as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology def strongerSubjects(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] > average_marks: output.append(subject) return output def weakerSubjects(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] < average_marks: output.append(subject) return output myStudent = Student(name="Aditya", roll="1234", phy=95, che=93, maths=54, history=70, geography=97, sociology=82) strong_subjects = myStudent.strongerSubjects() weaker_subjects = myStudent.weakerSubjects() print("{} is strong in {}".format(myStudent.Name, strong_subjects)) print("{} is weak in {}".format(myStudent.Name, weaker_subjects)) |
Output:
1 2 3 4 |
Aditya is strong in ['Physics', 'Chemistry', 'Geography', 'Sociology'] Aditya is weak in ['Maths', 'History'] |
You might observe that we are calculating the average marks in both the methods that are defined above. So, instead of repeating the code, we can define a method to calculate the average marks of the student. Here, the method to calculate the average marks has no significance outside the class definition as we don’t need the average marks of the student. Therefore, to calculate the average marks of the student, we will define a private method. This is so because we don’t need to calculate the average marks of the students. Here, we can define a private method __averageMarks()
to calculate the average and reuse the code as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology def __averageMarks(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 return average_marks def strongerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] > average_marks: output.append(subject) return output def weakerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] < average_marks: output.append(subject) return output myStudent = Student(name="Aditya", roll="1234", phy=95, che=93, maths=54, history=70, geography=97, sociology=82) strong_subjects = myStudent.strongerSubjects() weaker_subjects = myStudent.weakerSubjects() print("{} is strong in {}".format(myStudent.Name, strong_subjects)) print("{} is weak in {}".format(myStudent.Name, weaker_subjects)) |
Output:
1 2 3 4 |
Aditya is strong in ['Physics', 'Chemistry', 'Geography', 'Sociology'] Aditya is weak in ['Maths', 'History'] |
Creating a separate private method for calculating the average marks gives us the following advantages.
- We can increase the modularity of the code by creating methods that perform atomic tasks. Also, we can do it without having the need to change how the public methods work.
- We can easily refactor the code of the private methods without changing the implementation of public methods. This makes our code more maintainable.
Can we access a private method in Python?
Private methods can be accessed directly only inside the class definition in Python. If we try to access them outside the class definition, an AttributeError
exception will occur as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology def __averageMarks(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 return average_marks def strongerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] > average_marks: output.append(subject) return output def weakerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] < average_marks: output.append(subject) return output myStudent = Student(name="Aditya", roll="1234", phy=95, che=93, maths=54, history=70, geography=97, sociology=82) average_marks = myStudent.__averageMarks() print("Average marks of {} is {}".format(myStudent.Name, average_marks)) |
Output:
1 2 3 4 5 6 7 |
Traceback (most recent call last): File "/home/aditya1117/PycharmProjects/pythonProject/string1.py", line 40, in <module> average_marks = myStudent.__averageMarks() AttributeError: 'Student' object has no attribute '__averageMarks' |
But, we can access the private methods in python indirectly. For this, let us first see how names of private methods are stored in python. To obtain the name of methods and fields in a class, we can use the dir()
function.
The dir()
function takes a python object as the input parameter and returns the name of all the methods and fields. We can obtain the names of all the methods in the Student class as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology def __averageMarks(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 return average_marks def strongerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] > average_marks: output.append(subject) return output def weakerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] < average_marks: output.append(subject) return output myStudent = Student(name="Aditya", roll="1234", phy=95, che=93, maths=54, history=70, geography=97, sociology=82) attributes = dir(myStudent) print("Attributes of {} are {}".format(myStudent.Name, attributes)) |
Output:
1 2 3 |
Attributes of Aditya are ['Name', 'Roll', '_Student__averageMarks', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'marks', 'strongerSubjects', 'weakerSubjects'] |
In the output, you can see that the name of the private method __averageMarks
has been written as ‘_Student__averageMarks
‘. It means the method name has been preceded by _Student
i.e. _className
. We can access the private method using the full name i.e. _className__methodName()
by appending an underscore and class name to the name of the private method as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
class Student: def __init__(self, name, roll, phy, che, maths, history, geography, sociology): self.Name = name self.Roll = roll self.marks = dict() self.marks["Physics"] = phy self.marks["Chemistry"] = che self.marks["Maths"] = maths self.marks["History"] = history self.marks["Geography"] = geography self.marks["Sociology"] = sociology def __averageMarks(self): total_marks = 0 for subject in self.marks: total_marks = total_marks + self.marks[subject] average_marks = total_marks / 6 return average_marks def strongerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] > average_marks: output.append(subject) return output def weakerSubjects(self): average_marks = self.__averageMarks() subjects = self.marks.keys() output = [] for subject in subjects: if self.marks[subject] < average_marks: output.append(subject) return output myStudent = Student(name="Aditya", roll="1234", phy=95, che=93, maths=54, history=70, geography=97, sociology=82) average_marks = myStudent._Student__averageMarks() print("Average marks of {} is {}".format(myStudent.Name, average_marks)) |
Output:
1 2 3 |
Average marks of Aditya is 81.83333333333333 |
Another way with which we can access private methods is to use public methods. Here, we can use the private method but we cannot call the private method directly. For instance, while getting the subjects with marks greater than average marks, we have used the private method in the weakerSubjects()
method and strongerSubjects()
method but we haven’t accessed that directly.
Conclusion
In this article, we have discussed what private methods are, and how we can implement them in Python. We have also seen how we can access a private method in python. But, I would suggest you not use a private method outside the class definition. Accessing a private method outside its class definition just violates the idea of why we define them.
I hope you enjoyed reading this article. Stay tuned for more informative articles.
Happy Learning.