Fundamentals 12 min read

What Do Single and Double Underscores Mean in Python? A Complete Guide

This article explains the five underscore naming patterns in Python—single leading, single trailing, double leading, double leading and trailing, and a solitary underscore—detailing their conventions, how name mangling works, and the impact on variable and method behavior with clear code examples.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
What Do Single and Double Underscores Mean in Python? A Complete Guide

This article introduces the various meanings and naming conventions of single and double underscores ("dunders") in Python, explains how name mangling works, and shows how it affects your own Python classes.

We will discuss five underscore patterns and their effects on Python program behavior:

Single leading underscore: _var

Single trailing underscore: var_

Double leading underscore: __var

Double leading and trailing underscore: __var__

Single underscore: _

1. Single leading underscore _var

A single leading underscore is a convention that signals to other programmers that the variable or method is intended for internal use only; the interpreter does not enforce any restriction.

“Hey, this is not really part of the public interface of the class. Just ignore it.”
class Test:
    def __init__(self):
        self.foo = 11
        self._bar = 23
>> t = Test()
>>> t.foo
11
>>> t._bar
23

The leading underscore does not prevent access; it is merely a hint. However, it does affect how names are imported from a module.

# This is my_module.py:

def external_func():
    return 23

def _internal_func():
    return 42
>> from my_module import *
>>> external_func()
23
>>> _internal_func()
NameError: name '_internal_func' is not defined

Wildcard imports skip names with a leading underscore unless the module defines an __all__ list. Regular imports are not affected.

>> import my_module
>>> my_module.external_func()
23
>>> my_module._internal_func()
42
Single leading underscore is a Python naming convention indicating internal use; it is not enforced by the interpreter.

2. Single trailing underscore var_

A trailing underscore is used to avoid naming conflicts with Python keywords.

>> def make_object(name, class):
    SyntaxError: "invalid syntax"
>>> def make_object(name, class_):
    ...     pass

PEP 8 explains this convention.

3. Double leading underscore __var

Names that start with double underscores trigger name mangling: the interpreter rewrites the attribute name to include the class name, preventing accidental overrides in subclasses.

class Test:
    def __init__(self):
        self.foo = 11
        self._bar = 23
        self.__baz = 23
>> t = Test()
>>> dir(t)
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bar', 'foo']

Only __baz is mangled to _Test__baz. When a subclass defines its own __baz, the original mangled name remains.

class ExtendedTest(Test):
    def __init__(self):
        super().__init__()
        self.foo = 'overridden'
        self._bar = 'overridden'
        self.__baz = 'overridden'
>> t2 = ExtendedTest()
>>> t2.foo
'overridden'
>>> t2._bar
'overridden'
>>> t2.__baz
AttributeError: 'ExtendedTest' object has no attribute '__baz'
>>> t2._ExtendedTest__baz
'overridden'
>>> t2._Test__baz
42

Name mangling also works for methods.

class MangledMethod:
    def __method(self):
        return 42
    def call_it(self):
        return self.__method()
>> MangledMethod().call_it()
42

4. Double leading and trailing underscore __var__

Names that both start and end with double underscores are not mangled; they are reserved for special Python “magic” methods such as __init__ or __call__. It is best to avoid creating your own names of this form.

5. Single underscore _

A solitary underscore is conventionally used as a throw‑away variable or placeholder in loops and unpacking, and in the interactive REPL it holds the result of the last expression.

for _ in range(32):
    print('Hello, World.')
>> car = ('red', 'auto', 12, 3812.4)
>>> color, _, _, mileage = car
>>> color
'red'
>>> mileage
3812.4
>> 20 + 3
23
>>> _
23
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]

Python Underscore Naming Patterns – Quick Reference

Underscore naming quick reference
Underscore naming quick reference
Original English article: https://dbader.org/blog/meaning-of-underscores-in-python Translator: Tai Ran
naming conventionsname manglingunderscoresPEP 8
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.