Name Mangling — Core Concepts

What Is Name Mangling?

Name mangling is Python’s mechanism for rewriting attribute names that begin with two (or more) underscores and don’t end with two underscores. Python transforms __attr inside a class MyClass into _MyClass__attr.

This transformation happens at compile time (when the bytecode is generated), not at runtime. It’s completely transparent — you don’t see the change in your source code, but it’s there in the compiled bytecode.

The Rules

Name mangling applies when all three conditions are met:

  1. The name starts with two or more underscores.
  2. The name does not end with two or more underscores.
  3. The name appears inside a class body.
NameMangled?Result (in class Foo)
__barYes_Foo__bar
___barYes_Foo___bar
__bar_Yes_Foo__bar_
__bar__NoStays __bar__ (dunder method)
_barNoStays _bar (single underscore convention)
barNoNo underscores, no mangling

The Real Purpose: Preventing Inheritance Collisions

Name mangling isn’t about privacy or security. Its primary purpose is to prevent attribute name collisions between parent and child classes.

The Problem Without Mangling

Imagine a base class with an internal counter:

class Base:
    def __init__(self):
        self._count = 0  # single underscore — just a convention

    def increment(self):
        self._count += 1

class Child(Base):
    def __init__(self):
        super().__init__()
        self._count = 100  # Accidentally overwrites Base's _count!

The child class didn’t mean to interfere with the parent’s counter, but both used the name _count.

The Solution With Mangling

class Base:
    def __init__(self):
        self.__count = 0  # Becomes _Base__count

    def increment(self):
        self.__count += 1  # Accesses _Base__count

class Child(Base):
    def __init__(self):
        super().__init__()
        self.__count = 100  # Becomes _Child__count — different attribute!

Now Base has _Base__count = 0 and Child has _Child__count = 100. They coexist without interference.

How to Access Mangled Names

You can still access mangled attributes from outside the class — Python isn’t enforcing privacy:

obj = Child()
print(obj._Base__count)   # 0
print(obj._Child__count)  # 100

This works, but the awkward syntax serves as a strong signal that you’re breaking encapsulation.

Common Misconception

“Double underscores make attributes private.” Python has no access control. Name mangling is about collision avoidance, not privacy. Any code can access _ClassName__attr if it wants to. The single underscore convention (_attr) is the Python community’s way of saying “private” — it’s a social contract, not a technical barrier.

When to Use Name Mangling

Use it when:

  • You’re writing a library or framework class that will be extensively subclassed.
  • You need an internal attribute that subclasses absolutely must not accidentally override.
  • You’re designing a class hierarchy where multiple levels might use similar attribute names.

Don’t use it when:

  • You just want a “private” attribute — use single underscore _attr instead.
  • You’re writing application code with simple class hierarchies.
  • You want to test internal state easily — mangled names make testing harder.

Gotchas

  • Dynamic access fails: getattr(obj, "__attr") won’t find _Class__attr. You need getattr(obj, "_Class__attr").
  • Pickle and serialization: Some serialization libraries struggle with mangled names because the stored name includes the class name.
  • Refactoring hazard: Rename the class, and all mangled names change. External code using _OldName__attr breaks silently.

One thing to remember: Name mangling rewrites __attr to _ClassName__attr at compile time. It’s not about privacy — it’s about preventing parent and child classes from accidentally stepping on each other’s internal attributes.

pythonadvancedoop

See Also