Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

Name-mangling is a lexical substitution mechanism in Python where the parser automatically alters any identifier within a class definition that begins with at least two leading underscores (__) and has no more than one trailing underscore. This transformation occurs at compile time and applies to any matching identifier in the class scope, including instance attributes, methods, local variables, global declarations, nested classes, and imported module names. The primary purpose of name-mangling is to prevent accidental name collisions. By prefixing the identifier with the class name, Python ensures that subclasses do not inadvertently override or shadow the internal identifiers of their parent classes when defining their own attributes or methods.

The Mangling Rule

When the Python parser encounters a matching identifier within a class block, it rewrites the identifier according to the following pattern:
_<ClassName>__<identifier_name>
  • _: A single leading underscore.
  • <ClassName>: The name of the enclosing class, with any leading underscores stripped.
  • __<identifier_name>: The original identifier name, including its double underscores.

Syntax Visualization

Because mangling is a purely lexical operation performed by the parser, it affects all matching tokens within the class body, regardless of their programmatic role.
class BaseNode:
    # Class attribute mangled to _BaseNode__class_var
    __class_var = 10 
    
    def __init__(self):
        # Instance attribute mangled to _BaseNode__state
        self.__state = "initialized"
        
        # NOT subject to name-mangling (ends with double underscores)
        self.__magic__ = True 
        
        # NOT subject to name-mangling (only one leading underscore)
        self._protected = True

    def __internal_method(self):
        # Local variable mangled to _BaseNode__local_flag
        __local_flag = True
        return __local_flag

node = BaseNode()


# Accessing the instance dictionary reveals the mangled instance attributes in memory
print(node.__dict__)

# Output: {'_BaseNode__state': 'initialized', '__magic__': True, '_protected': True}

Accessing Mangled Identifiers

Name-mangling is a text-substitution operation rather than a strict memory-protection mechanism (like private in C++ or Java). The identifier remains fully accessible from outside the class if the mangled name is explicitly invoked.
class NetworkClient:
    def __init__(self):
        self.__timeout = 30

    def get_timeout(self):
        # Internal access uses the original identifier; 
        # the parser has already translated this to self._NetworkClient__timeout
        return self.__timeout

client = NetworkClient()


# Internal access resolves correctly
print(client.get_timeout())  # Output: 30


# External access using the original identifier fails

# print(client.__timeout)    # Raises AttributeError: 'NetworkClient' object has no attribute '__timeout'


# External access using the mangled identifier succeeds
print(client._NetworkClient__timeout)  # Output: 30

Lexical Edge Cases

  1. Dunder Identifiers: Identifiers that both begin and end with double underscores (e.g., __init__, __dict__) are strictly exempt from name-mangling.
  2. Class Name Stripping: If the class name itself begins with an underscore, those leading underscores are stripped during the mangling process. For example, the identifier __value inside class _Hidden: becomes _Hidden__value, not __Hidden__value.
  3. Scope Limitation: Name-mangling only occurs within the lexical scope of a class definition. Variables defined with double underscores at the module level or inside standalone functions are not mangled.
  4. String Evaluation: Functions like getattr(), setattr(), or hasattr() evaluate strings at runtime, bypassing the compile-time parser. They do not automatically mangle strings. You must pass the fully mangled string (e.g., getattr(obj, "_ClassName__attr")) to interact with the attribute dynamically.
Master Python with Deep Grasping Methodology!Learn More