Question

Single vs Double Leading Underscores in Python

pythonoopnaming-conventionsidentifier

Question

In Python, what do single and double leading underscores before an object's name mean?

For example, what is the difference between names such as:

_name
__name

How does Python treat these names, and what do they communicate to other developers?

Short Answer

By the end of this page, you will understand what leading underscores mean in Python, the difference between _name and __name, when Python applies name mangling, and how these naming styles are used in real code to signal intent and avoid accidental misuse.

Concept

In Python, leading underscores in names are mainly about convention and intent.

Single leading underscore: _name

A single leading underscore usually means:

  • "This is internal"
  • "This is meant for use inside this module or class"
  • "You can access it, but you probably should not unless you know what you are doing"

Python does not make _name truly private. It is only a naming convention.

Example:

class User:
    def __init__(self):
        self._token = "secret"

You can still do this:

user = User()
print(user._token)

That works. The underscore is a signal to developers, not a hard restriction.

A single leading underscore also matters for from module import *. By default, names starting with _ are not imported.

Double leading underscore: __name

A double leading underscore inside a class triggers name mangling.

Python changes the name internally to reduce accidental access or accidental overriding in subclasses.

Example:

class User:
    def __init__(self):
        self.__token = "secret"

Python internally rewrites __token to something like:

_User__token

So this will fail:

user = User()
# print(user.__token)  # AttributeError

But this will work:

print(user._User__token)

This shows that double underscores do not create true privacy. They mainly prevent accidental name collisions.

Why this matters

This naming system helps developers:

  • communicate which attributes are part of the public API
  • separate internal implementation details from public usage
  • avoid accidental overrides in inheritance
  • write clearer, more maintainable code

In short:

  • _name = internal by convention
  • __name = name-mangled inside classes to avoid collisions

Mental Model

Think of Python names like rooms in a building.

  • name is a public room with an open door.
  • _name is a room with a sign saying staff only. The door is not locked, but people are expected to respect the sign.
  • __name is a room whose label is changed behind the scenes, so it is harder to walk into by accident.

The important idea is that Python prefers trust and convention over strict access control. Instead of blocking access completely, it gives signals about what should and should not be used directly.

Take Quiz

Syntax and Examples

Basic syntax

class Example:
    def __init__(self):
        self.public = 1
        self._internal = 2
        self.__mangled = 3

Accessing each attribute

obj = Example()

print(obj.public)       # 1
print(obj._internal)    # 2
# print(obj.__mangled)  # AttributeError
print(obj._Example__mangled)  # 3

What this means

  • public is meant to be used freely.
  • _internal is a non-public attribute by convention.
  • __mangled is name-mangled by Python.

Example with inheritance

class Parent:
    def __init__(self):
        self._value = "parent internal"
        self.__secret = "parent secret"

class Child(Parent):
    def __init__(self):
        super().__init__()
        self.__secret = "child secret"

child = Child()
print(child._value)
print(child._Parent__secret)
print(child._Child__secret)

Why this example matters

If both Parent and Child define __secret, Python mangles them differently:

  • _Parent__secret
  • _Child__secret

That avoids accidental collisions between parent and child classes.

Step by Step Execution

Consider this example:

class Account:
    def __init__(self):
        self._balance = 100
        self.__pin = 4321

account = Account()
print(account._balance)
print(account._Account__pin)

Step by step

  1. Python starts defining the Account class.
  2. Inside __init__, two instance attributes are assigned.
  3. self._balance = 100
    • Python stores an attribute literally named _balance.
    • No special transformation happens.
  4. self.__pin = 4321
    • Because it starts with two underscores and is inside a class, Python mangles the name.
    • Internally, it becomes _Account__pin.
  5. account = Account() creates an instance and runs __init__.
  6. print(account._balance) works because _balance exists with that exact name.
  7. print(account._Account__pin) works because that is the mangled internal name.

What would fail

print(account.__pin)

This raises AttributeError because the instance does not have an attribute literally named __pin. It was renamed internally.

Real World Use Cases

1. Marking internal helper methods

Libraries often use a single underscore for methods that are not part of the public API.

class Parser:
    def parse(self, text):
        return self._clean(text)

    def _clean(self, text):
        return text.strip().lower()

Here, parse() is public, while _clean() is an internal implementation detail.

2. Avoiding subclass name collisions

Double underscores are useful when a base class wants to protect an internal attribute from being accidentally replaced by a subclass.

class BaseLogger:
    def __init__(self):
        self.__prefix = "LOG"

A subclass can define its own __prefix without overwriting the base class's version.

3. Hiding module internals from wildcard imports

In modules, names with a single leading underscore are treated as non-public.

_helper_value = 10
public_value = 20

With:

from mymodule import *

_helper_value is usually not imported.

4. Building stable public APIs

When writing reusable packages, developers often expose only public names and keep underscored names flexible so they can change them later without breaking users.

Take Quiz

Real Codebase Usage

In real projects, underscores are used as part of API design.

Public vs internal attributes

Developers commonly separate names like this:

class ReportService:
    def generate(self):
        data = self._fetch_data()
        return self._format(data)

    def _fetch_data(self):
        return [1, 2, 3]

    def _format(self, data):
        return ", ".join(str(x) for x in data)

The public method is generate(). The underscored methods support it internally.

Guarding against accidental overrides

In frameworks and large class hierarchies, double underscores may be used when a base class must keep an internal attribute separate.

class Base:
    def __init__(self):
        self.__state = {}

This reduces the chance that a subclass accidentally reuses the same attribute name.

Encapsulation by convention

Python codebases usually rely more on conventions, documentation, and properties than on strict privacy.

Example with a property:

class Product:
    def __init__(self, price):
        self._price = price

    @property
    def price(self):
        return self._price

Here, _price is internal storage and price is the public interface.

Testing and maintenance

In real code, developers may still access _internal names in tests or debugging, but they try not to depend on them unless necessary because those internals may change.

Common Mistakes

Mistake 1: Thinking _name is private

Broken assumption:

class Demo:
    def __init__(self):
        self._value = 10

obj = Demo()
print(obj._value)  # This works

A single underscore does not block access. It only signals internal use.

Mistake 2: Thinking __name means true privacy

class Demo:
    def __init__(self):
        self.__value = 10

obj = Demo()
print(obj._Demo__value)  # Still accessible

Double underscores use name mangling, not true private access control.

Mistake 3: Overusing double underscores

Many beginners use __name everywhere. That often makes code harder to debug and extend.

Use double underscores only when you specifically want to avoid name collisions in subclasses.

Mistake 4: Forgetting name mangling only applies inside classes

Name mangling happens for class attributes and methods with double leading underscores. It is not a general Python rule for every variable.

Mistake 5: Confusing __name__ with name mangling

Names like __init__, __str__, and __name__ are different. These are often called dunder names.

class Demo:
    def __str__(self):
        return "Demo object"

These are special Python-defined names, not private attributes.

Mistake 6: Using wildcard imports and expecting underscored names

from mymodule import *

Beginners may expect _helper to be imported too. Usually it is skipped because it starts with _.

Comparisons

Name styleExampleMeaningEnforced by Python?Common use
PublicnameIntended for normal useNo restriction neededPublic API
Single leading underscore_nameInternal by conventionNoInternal helpers, non-public attributes
Double leading underscore__nameName-mangled in classesPartly, via renamingAvoiding subclass collisions
Double leading and trailing underscore__init__Special Python-defined nameYes, special meaningMagic methods / dunder methods

_name vs __name

Feature_name__name
Signals internal useYesYes
Directly accessible as writtenYesNo, usually mangled
Prevents accidental subclass collisionsNoYes
Best for everyday internal attributesYesUsually yes
Best when inheritance collisions are a concernNoYes

When to use which

  • Use name for public attributes and methods.
  • Use _name for internal details.
  • Use __name only when name mangling is actually helpful.
  • Use __init__-style names only for Python special methods defined by the language.
Take Quiz

Cheat Sheet

Quick rules

  • name → public
  • _name → internal by convention
  • __name → name-mangled inside classes
  • __name__ → special Python-defined name

Examples

class Example:
    def __init__(self):
        self.value = 1
        self._value = 2
        self.__value = 3

Access:

obj = Example()
print(obj.value)            # works
print(obj._value)           # works
print(obj._Example__value)  # works
# print(obj.__value)        # AttributeError

Key facts

  • Single underscore is a convention, not privacy.
  • Double underscore triggers name mangling in classes.
  • Name mangling helps avoid accidental collisions in subclasses.
  • Double underscore on both sides, like __init__, is a special method name, not a private name.
  • Names starting with _ are usually skipped by from module import *.

Rule of thumb

  • Default to public names when something is part of the API.
  • Use _name for internal implementation details.
  • Use __name sparingly and only when inheritance-related protection is useful.

FAQ

Is _variable private in Python?

No. It is only a convention that says the name is internal and should not usually be accessed directly.

Is __variable truly private?

No. Python mangles the name, but it can still be accessed using its mangled form, such as _ClassName__variable.

Why does Python use conventions instead of strict private members?

Python emphasizes readability, trust, and developer responsibility. Conventions are often enough and keep the language flexible.

What is name mangling in Python?

Name mangling is when Python rewrites a class attribute like __value to something like _ClassName__value to avoid accidental name collisions.

Should I use double underscores for all internal attributes?

Usually no. Most internal attributes should use a single underscore. Double underscores are mainly useful when inheritance could cause collisions.

Is __init__ the same as __value?

No. __init__ is a special built-in method name with meaning defined by Python. __value is a regular name that gets mangled inside a class.

Why is _name skipped in from module import *?

Because Python treats names starting with a single underscore as non-public during wildcard imports.

Can subclasses access double-underscore attributes?

Not directly by the original name. They would need the mangled name, and each class gets its own mangled version.

Take Quiz

Mini Project

Description

Create a small Python class that demonstrates public, internal, and name-mangled attributes. This project helps you see how underscore naming affects access, readability, and inheritance in practical code.

Goal

Build a class and subclass that show the difference between name, _name, and __name in action.

Requirements

  • Create a base class with one public, one single-underscore, and one double-underscore attribute.
  • Add a method that prints the values from inside the class.
  • Create a subclass that defines its own double-underscore attribute with the same name.
  • Instantiate the subclass and show which attributes are accessible from outside.
  • Demonstrate the mangled names for both base and subclass attributes.
Take Quiz

Keep learning

Related questions

View more