Skip to main content
HomeTutorialsPython

Python Private Methods Explained

Learn about private methods in Python, their syntax, how and when to use them in your projects using examples, and the best practices.
Mar 2024  · 9 min read

In Object-Oriented Programming (OOP), a software design approach, we use “objects” to model real-world entities. An object is a data structure with attributes (data) and methods (functions) that act on the data. Complex systems can be easier to design with objects.

Learn more about the fundamentals and software engineering concepts behind OOP by starting our object-oriented programming with Python course.

Encapsulation is a fundamental concept in OOP. It means grouping the data and the methods of an object and hiding the details from the outside world. Think of encapsulation as a process that creates a ‘capsule’ (an object) with its own data and ways to manipulate it.

The main purpose of encapsulation is to:

  • Prevent direct access to the data (data integrity).
  • Simplify the system by showing only what is needed (abstraction).

Private methods are key to achieving this encapsulation by hiding the internal implementation details of a class.

By making a method private, you tell other programmers that this method is not intended to be accessed directly. This can prevent bugs and errors by ensuring that the internal state of an object can only be changed in controlled ways.

Here, we will introduce private methods, the syntax for defining them, implementing private methods in real-world examples, and the best practices for using them.

What Are Private Methods?

Private methods in object-oriented programming (OOP) are functions within a class designed for internal use only. They encapsulate a class’s functionality, ensuring its internal workings remain shielded from external interaction.

This encapsulation provides a layer of abstraction, allowing the class to maintain control over its internal state and behavior and to change its implementation without affecting external code that relies on it.

In Python, the convention to denote private methods is by prefixing the method name with a single underscore (_) or double underscores (__). This serves as a hint to developers about the method's intended scope and merely a convention.

Although this convention does not enforce strict privacy like in some other languages, it is a well-respected practice within the Python community for signaling the method's intended usage. Later, we will delve deeper into these aspects more comprehensively.

The Syntax of Private Methods

There are two different ways to define private methods, which we will see through examples.

We can define a private method using a single underscore before the function name:

class MyClass:
   def _private_method(self):
       print("This is a private method")

This definition is merely a convention for the programmers as the function is still accessible outside the class, though it is not recommended.

If this is the first time you’ve heard about classes in Python, we recommend checking out our beginner-friendly tutorial on Classes first.

Let us create an object and try to access the created private method:

# Creating an object
obj = MyClass()

# Accessing from outside
obj._private_method()  # Not recommended to call directly, but possible

There is another syntax for defining private methods in Python using double underscores. It looks like this: :

class MyClass:
   def __private_method(self):
       print("This is a private method")

obj = MyClass()
# obj.__private_method()  # This will raise an AttributeError

When we try to access the private method from outside the class, it throws an AttributeError, signaling that it cannot be directly accessed using the function name.

To summarize the private methods syntax in Python:

  • Single underscore: merely a convention for the programmers, can be accessed outside the function.
  • Double underscore: cannot be accessed outside the function with just the function name. It still can be accessed through “Name Mangling” which we will see later in this tutorial.

Implementing Private Methods in Python

As a real-world example, consider a secure and user-friendly BankAccount class to manage financial transactions for a user. The requirements of bank accounts are:

  • The class must encapsulate the account holder's balance, allowing for deposits and withdrawals while ensuring that the balance cannot be directly manipulated outside the class.
  • The class should facilitate safe transfers between accounts, updating the balance of the recipient account without exposing the internal mechanism for balance modification.
  • The solution must adhere to the principles of object-oriented programming, specifically encapsulation and abstraction, to maintain the integrity of the account's data and provide a clear, simple interface for interacting with the account.

Of course, a bank account needs more functionalities such as balance checking, currency conversion, and interest handling — but to keep things simple, we’ll ignore these in our implementation.

Let’s implement this solution and understand the code.

class BankAccount:
   def __init__(self, account_holder, initial_balance=0):
       self.account_holder = account_holder
       self.__balance = initial_balance  # Private attribute

   def deposit(self, amount):
       if amount > 0:
           self.__balance += amount
           print(f"Deposited ${amount}. New balance: ${self.__balance}")
       else:
           print("Deposit amount must be positive.")

   def withdraw(self, amount):
       if 0 < amount <= self.__balance:
           self.__balance -= amount
           print(f"Withdrew ${amount}. New balance: ${self.__balance}")
       else:
           print("Insufficient funds or invalid amount.")

   def __update_balance(self, amount):  # Private method
       self.__balance += amount

   def transfer(self, amount, other_account):
       if 0 < amount <= self.__balance:
           self.withdraw(amount)
           other_account.__update_balance(amount)
           print(f"Transferred ${amount} to {other_account.account_holder}.")
       else:
           print("Insufficient funds or invalid amount.")

We first create a BankAccountclass, that wraps all intended behaviors and functionality required by a BankAccount object.

The BankAccount class has a private attribute __balance and a private method __update_balance:

  • Private variable (__balance): This is an attribute of the BankAccount class that stores the current account balance. It is marked as private by prefixing its name with two underscores (__). This means it is intended to be accessed only within the class itself. For example, it is modified by the deposit, withdraw, and __update_balance methods. External access to this attribute is not recommended.
  • Private method (__update_balance): The purpose of this method is to update the account balance. It is called by the transfer method to update the balance of the recipient account during a transfer operation. Using a private method here helps encapsulate the logic for updating the balance, ensuring that it can only be done in controlled ways defined by the class.

Feel free to create a new Python file, copy and paste the code above and below, and execute it to see it yourself.

# Using the Bank Account Solution
account1 = BankAccount("John Doe", 1000)
account2 = BankAccount("Jane Doe", 500)

account1.deposit(200)
account1.withdraw(100)
account1.transfer(300, account2)

You’ll see the output below:

Deposited $200. New balance: $1200
Withdrew $100. New balance: $1100
Withdrew $300. New balance: $800
Transferred $300 to Jane Doe.

Congratulations ! You have created your BankAccount solution using a private method!

Based on the output, we see that when performing the usual banking operations such as depositing, withdrawing, and transferring funds, the usual logical behavior of a bank account is followed.

The __init__ method: is it a private method?

You probably noticed the __init__ method used in the Bank Account example. Since it also uses the double underscores syntax, you may wonder if it’s a private method too.

The __init__ method is not considered a private method in the same way that methods prefixed with double underscores for privacy are.

Instead, it is a part of special methods in Python, often referred to as a "dunder" method (short for "double underscore"), which has a specific purpose in the language. Other examples of such special methods include __str__, __repr__, and __del__.

Let us understand how this special method was utilized in our example:

class BankAccount:
   def __init__(self, account_holder, initial_balance=0):
       self.account_holder = account_holder
       self.__balance = initial_balance

As we see, the __init__ method is the constructor for a class. It is automatically called when a new instance of the class is created, and it is used to initialize the object's attributes. For the BankAccount class, the __init__ method is used to set the initial values for the account_holder and __balance attributes.

Advanced Concepts: Name Mangling in Python

Earlier in our definition, we mentioned that private methods in Python are merely a convention, and the Python language does not strictly enforce privacy, unlike other programming languages.

Rightly so, we saw that the private methods could be accessed directly when using a single underscore, but the access was restricted when using a double underscore.

Why, though? Because of a concept called “name mangling” in Python.

When you prefix an attribute name with double underscores, Python automatically modifies the name by adding a single underscore and the class name before the original attribute name.

This modified name is how the attribute is stored internally within the class. The process of modifying the name in this way is known as name mangling.

Name mangling is useful for two reasons:

  • Preventing name conflicts: In inheritance, if a subclass defines an attribute with the same name as an attribute in its superclass, the two would conflict. Name mangling helps avoid this issue by ensuring that the names are unique to each class.
  • A degree of privacy: While Python does not have true private attributes, name mangling provides a way to make attributes less accessible from outside the class, thus offering a degree of privacy.

Let’s see an example to understand better.

class MyClass:
   def __init__(self):
       self.__private_attribute = "I am private"

   def __private_method(self):
       print("This is a private method")

obj = MyClass()
print(obj.__private_attribute)  # This will raise an AttributeError

In this example, __private_attribute and __private_method are name-mangled. Internally, they are stored as _MyClass__private_attribute and _MyClass__private_method, respectively. Trying to access them using their original names from outside the class will result in an AttributeError.

However, you can still access them using their mangled names:

print(obj._MyClass__private_attribute)  # This will print "I am private"
obj._MyClass__private_method()  # This will print "This is a private method"

While name mangling makes attributes less accessible, it’s important to note that this is not a foolproof way to ensure privacy in Python. It’s more of a convention to indicate that an attribute is intended for internal use within the class.

Best Practices For Using Private Methods & Variables

Effectively leveraging private methods and variables requires adherence to certain best practices. These practices help ensure that your code is not only functional but also clear, maintainable, and secure.

Here are some best practices to follow:

  • Use a single underscore for “Protected” attributes. If you want to indicate that an attribute or method is intended for use within the class and its subclasses but not for external use, prefix it with a single underscore (_). This is a convention in Python that signals to other developers that the attribute or method is "protected" and should not be accessed directly.
  • Use double underscore for “Private” attributes. If you want to make an attribute or method less accessible outside the class to avoid accidental modification or usage, prefix it with a double underscore (__). This triggers name mangling and makes it harder (but not impossible) to access the attribute or method from outside the class.
  • Use private methods for internal logic. Private methods (those with a single or double underscore prefix) are a great way to encapsulate the internal logic of your class. Use them to perform tasks that are specific to the class’s implementation and should not be exposed as part of the class’s public interface.

Finally, it’s important to be consistent with your coding best practices. Stick to the naming conventions and use them consistently throughout your codebase. This makes your code easier to understand and maintain for other developers and your future self.

Conclusion

This tutorial introduced you to the concepts behind private methods, their syntax, and when you can use them. We also saw multiple examples illustrating how you can potentially use them in your next coding project. Finally, we looked at some best practices to keep in mind when using them.

For further learning, you can check out the Python Programming Skill Track and the Object-oriented Programming in Python course.


Photo of Arunn Thevapalan
Author
Arunn Thevapalan

As a senior data scientist, I design, develop and deploy large-scale machine-learning solutions to help businesses make better data-driven decisions. As a data science writer, I share learnings, career advice, and in-depth, hands-on tutorials.

Topics

Continue Your Python Learning Journey!

Course

Data Privacy and Anonymization in Python

4 hr
2.5K
Learn to process sensitive information with privacy-preserving techniques.
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related

Becoming Remarkable with Guy Kawasaki, Author and Chief Evangelist at Canva

Richie and Guy explore the concept of being remarkable, growth, grit and grace, the importance of experiential learning, imposter syndrome, finding your passion, how to network and find remarkable people, measuring success through benevolent impact and much more. 
Richie Cotton's photo

Richie Cotton

55 min

Exponents in Python: A Comprehensive Guide for Beginners

Master exponents in Python using various methods, from built-in functions to powerful libraries like NumPy, and leverage them in real-world scenarios to gain a deeper understanding.
Satyam Tripathi's photo

Satyam Tripathi

9 min

Python Linked Lists: Tutorial With Examples

Learn everything you need to know about linked lists: when to use them, their types, and implementation in Python.
Natassha Selvaraj's photo

Natassha Selvaraj

9 min

A Beginner’s Guide to Data Cleaning in Python

Explore the principles of data cleaning in Python and discover the importance of preparing your data for analysis by addressing common issues such as missing values, outliers, duplicates, and inconsistencies.
Amberle McKee's photo

Amberle McKee

11 min

Python Data Classes: A Comprehensive Tutorial

A beginner-friendly tutorial on Python data classes and how to use them in practice
Bex Tuychiev's photo

Bex Tuychiev

9 min

Estimating The Cost of GPT Using The tiktoken Library in Python

Learn to manage GPT model costs with tiktoken in Python. Explore tokenization, BPE, and estimate OpenAI API expenses efficiently.
Moez Ali's photo

Moez Ali

7 min

See MoreSee More