Languages like Java and C++ have access modifiers (private, protected, public) to prohibit external access to class members. Python, however, does not have “private” variables in the strict sense (variables that are completely inaccessible from the outside) within its language specification.
However, Python provides a feature to pseudo-hide members from the outside by prefixing variables with two underscores (__). This article explains how to define variables using __ and the mechanism behind it, known as “Name Mangling.”
Hiding Variables with Double Underscore (__)
If you prefix a variable or method name with __ (two underscores) inside a class, that member cannot be directly referenced from outside the class.
As an example, let’s create a class that manages database connection information. Important information like connection passwords is data we don’t want inadvertently accessed from the outside.
class DatabaseConnector:
def __init__(self, user, password):
self.user = user
# Prefix with __ to make it a private variable
self.__password = password
def __connect_internal(self):
"""Internal connection process (Private method)"""
print(f"Connected as user {self.user} with password {self.__password}.")
def execute(self):
"""Public method"""
print("Starting process.")
# Private members can be accessed from inside the class
self.__connect_internal()
print("Process complete.")
# Instantiation
db = DatabaseConnector("admin", "secret1234")
# Execution via public method succeeds
db.execute()
Output:
Starting process.
Connected as user admin with password secret1234.
Process complete.
From inside the class method (execute), we can access __password and __connect_internal without any issues.
Error When Accessing from Outside
Now, let’s see what happens if we try to access these members directly from outside the class.
# Trying to access the private variable from outside
try:
print(db.__password)
except AttributeError as e:
print(f"Error occurred: {e}")
# Trying to call the private method from outside
try:
db.__connect_internal()
except AttributeError as e:
print(f"Error occurred: {e}")
Output:
Error occurred: 'DatabaseConnector' object has no attribute '__password'
Error occurred: 'DatabaseConnector' object has no attribute '__connect_internal'
From the outside, it appears as if these members are hidden, raising an AttributeError saying “no such attribute exists.”
Mechanism: Name Mangling
The mechanism by which Python achieves this hiding is actually quite simple. It doesn’t strictly prohibit access; it just “automatically renames the variables.” This is called “Name Mangling.”
Members starting with __ are internally converted to the name _ClassName__VariableName. You can see this reality by using the dir() function to check the list of attributes an instance holds.
# Display the list of instance attributes
print(dir(db))
Output (excerpt):
['_DatabaseConnector__connect_internal', '_DatabaseConnector__password', 'execute', 'user', ...]
You can find names like _DatabaseConnector__password in the list. This is the true identity of __password.
Accessing via Mangled Names
This means that if you use the converted name, you can access it even from the outside.
# Force access using the mangled name
print(f"Backdoor access: {db._DatabaseConnector__password}")
Output:
Backdoor access: secret1234
As shown, Python’s private variables are not “completely inaccessible” but rather “made harder to access (to prevent accidental collisions).”
Usage Distinction with Single Underscore (_)
Python also has a convention of using variables starting with a single underscore (_, e.g., _variable).
_variable(Single Underscore): A “gentleman’s agreement” among developers meaning “This is for internal use, so please don’t touch it from the outside.” It does not enforce access restrictions or perform name mangling.__variable(Double Underscore): Name mangling is performed. This is primarily used to prevent variable name collisions between a parent class and a child class when inheriting.
Generally, the design guideline in Python is to use the single underscore (_) if you simply intend to indicate “private/internal use,” and use the double underscore (__) only when you want to strictly avoid name collisions in class inheritance structures.
Summary
- Prefixing variable or method names with
__makes them inaccessible directly from the outside. - This is due to “Name Mangling,” which converts the name to
_ClassName__MemberName. - It is not complete hiding in a security sense.
- For general “private” indication, using a single underscore (
_) is recommended.
