NeuroAgent

Python Underscore Naming Conventions Explained

Learn the difference between single and double leading underscores in Python. Discover name mangling, access control conventions, and when to use each underscore type in your code.

Question

What do single and double leading underscores before an object’s name represent in Python?

NeuroAgent

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)

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_var from 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.

python
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 __var into _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.”

python
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 classname is the name of the current class with leading underscore(s) stripped

Example transformation:

python
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

python
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

python
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

python
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
python
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

  1. Single and Double Underscores in Python Names – Real Python
  2. What is the meaning of single and double underscore before an object name? - Stack Overflow
  3. Private Methods - Single or Double Underscore - Reddit
  4. The Meaning of Underscores in Python – dbader.org
  5. Single and Double Underscores in Python explained - Medium
  6. What is the meaning of single and double leading underscore in Python - Python Engineer
  7. PEP 8 – Style Guide for Python Code
  8. What’s the Meaning of Single and Double Underscores In Python? - Reddit
  9. Python double underscore mangling - Stack Overflow
  10. Single underscore and Double underscore in Python OOP - Medium
  11. Name Mangling in Python | Tech Tutorials
  12. What is Name Mangling in Python and How Does it Work With Detailed Examples
  13. Name Mangling in Python with Example
  14. 9. Classes — Python 3.14.0 documentation
  15. Python – Private Members In Class and Name Mangling
  16. Name mangling in Python - GeeksforGeeks