What do single and double leading underscores before an object’s name represent in Python?
Single and double leading underscores in Python serve as naming conventions to indicate the intended visibility and usage of variables, methods, and attributes. A single leading underscore (_) signals that a name is intended for internal use within a class or module, while a double leading underscore (__) triggers name mangling, which transforms the name to help prevent accidental name conflicts in inheritance scenarios. These conventions are not true access modifiers but rather cultural signals to developers about how these elements should be treated.
Contents
- Single Leading Underscore (_var)
- Double Leading Underscore (__var)
- Name Mangling Mechanics
- Python’s Approach to Access Control
- Practical Examples and Use Cases
- When to Use Each Convention
- Special Cases: Dunder Methods
Single Leading Underscore (_var)
A single leading underscore is a widely adopted convention in Python that indicates a name is intended for internal use. When you see a variable or method name starting with a single underscore, it’s signaling to other developers that this element should not be used outside of the class or module where it’s defined.
Key characteristics:
-
No enforcement by Python: Unlike in some other languages, Python doesn’t actually prevent access to names with a single leading underscore. You can still access
_internal_varfrom outside the class, but the convention warns you not to. -
“Protected” concept: This is Python’s closest equivalent to the “protected” access modifier found in languages like Java or C++, though it’s only a convention rather than a language-enforced restriction.
-
Common usage: Often used for methods and attributes that are part of the internal implementation of a class but might be useful for subclasses or for debugging.
class MyClass:
def __init__(self):
self._internal_var = 42 # Internal use
def _internal_method(self):
return "This is internal"
def public_method(self):
return self._internal_method()
According to Python Engineer, single underscores are primarily about developer communication rather than language enforcement.
Double Leading Underscore (__var)
A double leading underscore triggers name mangling, which is a transformation mechanism that changes the name of an attribute to help prevent conflicts in inheritance scenarios. This is Python’s closest equivalent to “private” access, though it’s still not truly private.
What name mangling does:
- Transforms
__varinto_ClassName__var - Only applies in class contexts (not at module level)
- Only affects names with exactly two leading underscores and at most one trailing underscore
As Real Python explains, “a double leading underscore triggers name mangling for class attributes and methods.” The Python documentation confirms that “the mangling rules are designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private.”
class MyClass:
def __init__(self):
self.__private_var = 42
obj = MyClass()
print(obj.__private_var) # Error! AttributeError
print(obj._MyClass__private_var) # Works: 42
Name Mangling Mechanics
Name mangling follows a specific algorithm defined in the Python language specification:
Transformation rule:
- Any identifier of the form
__var_name(at least two leading underscores or at most one trailing underscore) is replaced with_classname__var_name - The
classnameis the name of the current class with leading underscore(s) stripped
Example transformation:
class Example:
def __init__(self):
self.__data = "secret"
# Before mangling: __data
# After mangling: _Example__data
As Nsikak Imoh explains, “any identifier of the form __var_name — at least two leading underscores or at most one trailing underscore — is replaced with _classname__var_name.”
Important limitations:
- Name mangling only occurs in class definitions, not at module level
- It doesn’t apply to names that start and end with double underscores (dunder methods)
- The transformation is purely textual and happens at compile time
- You can still access mangled names directly if needed
Python’s Approach to Access Control
Unlike languages such as Java, C++, or C#, Python does not have true access modifiers. As noted in the Reddit discussion, “Python doesn’t support access modifiers, and protected especially makes zero sense in Python.”
Python’s philosophy:
- “We’re all consenting adults here” - developers are trusted to follow conventions
- Name mangling exists primarily to prevent accidental name conflicts in inheritance
- True privacy is not the main goal of double underscores
Comparison with other languages:
| Language | Private | Protected | Public |
|---|---|---|---|
| Python | Convention (__var) | Convention (_var) | Default |
| Java | private |
protected |
Default |
| C++ | private: |
protected: |
Default |
According to PEP 8, “double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.”
Practical Examples and Use Cases
Example 1: Basic name mangling
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Name mangling occurs
def deposit(self, amount):
self.__balance += amount
def get_balance(self):
return self.__balance
account = BankAccount(1000)
# print(account.__balance) # AttributeError!
print(account._BankAccount__balance) # Works: 1000
Example 2: Inheritance and name conflicts
class Base:
def __init__(self):
self.__private = "Base private"
class Derived(Base):
def __init__(self):
super().__init__()
self.__private = "Derived private" # No conflict!
d = Derived()
print(d._Base__private) # "Base private"
print(d._Derived__private) # "Derived private"
As GeeksforGeeks explains, name mangling “is designed mostly to avoid accidents; it still is possible to access or modify a variable that is considered private.”
Example 3: When name mangling doesn’t apply
class MyClass:
def __init__(self):
self.__dunder_method__() # This won't be mangled
def __dunder_method__(self):
print("This is a special method")
obj = MyClass() # Prints: "This is a special method"
When to Use Each Convention
Use single underscore (_var) when:
- You want to indicate internal use but still allow access
- You’re creating methods or attributes that might be useful for subclasses
- You want to signal that something is implementation detail
- You’re following the “protected” convention from other languages
Use double underscore (__var) when:
- You want to prevent accidental name conflicts in inheritance
- You’re creating attributes that should not be easily accessible
- You’re working with classes that are designed to be subclassed
- You want to make it clear that something is implementation-private
According to dbader.org, “name mangling is not applied if a name starts and ends with double underscores” - these are reserved for special methods.
Special Cases: Dunder Methods
Names that start and end with double underscores (like __init__, __str__, __add__) are dunder (double underscore) methods and are treated specially:
Key characteristics:
- Not mangled: These names are left unchanged by the name mangling process
- Special meaning: They implement or override special behaviors in Python
- Convention: Should only be used to implement or override existing special methods
class MyClass:
def __init__(self): # Not manged!
self.value = 42
def __str__(self): # Not manged!
return str(self.value)
def __private_method(self): # This is mangled!
return "private"
As noted in the research, “Names with double leading and trailing underscores are reserved for special use in Python” and are “left unscathed by the Python interpreter.”
Conclusion
Python’s underscore naming conventions provide a way to indicate the intended visibility and usage of code elements, even though the language doesn’t enforce true access control. Single leading underscores signal internal use, while double leading underscores trigger name mangling to prevent conflicts in inheritance.
Key takeaways:
- Single underscores (_var) are conventions for internal/protected access
- Double underscores (__var) trigger name mangling to _ClassName__var
- Python doesn’t have true private access - these are conventions, not language features
- Name mangling helps prevent accidental name conflicts in inheritance
- Dunder methods (method) are special and not mangled
Recommendations:
- Use single underscores for implementation details that might be useful to subclasses
- Use double underscores for truly internal implementation details
- Remember that both conventions can be bypassed if needed
- Follow Python’s “consenting adults” philosophy - document your intentions clearly
These naming conventions are part of what makes Python flexible and developer-friendly, trusting programmers to use their best judgment while providing helpful mechanisms to prevent common mistakes.
Sources
- Single and Double Underscores in Python Names – Real Python
- What is the meaning of single and double underscore before an object name? - Stack Overflow
- Private Methods - Single or Double Underscore - Reddit
- The Meaning of Underscores in Python – dbader.org
- Single and Double Underscores in Python explained - Medium
- What is the meaning of single and double leading underscore in Python - Python Engineer
- PEP 8 – Style Guide for Python Code
- What’s the Meaning of Single and Double Underscores In Python? - Reddit
- Python double underscore mangling - Stack Overflow
- Single underscore and Double underscore in Python OOP - Medium
- Name Mangling in Python | Tech Tutorials
- What is Name Mangling in Python and How Does it Work With Detailed Examples
- Name Mangling in Python with Example
- 9. Classes — Python 3.14.0 documentation
- Python – Private Members In Class and Name Mangling
- Name mangling in Python - GeeksforGeeks