Start learning free

LESSON 181 OF 344 · OBJECT-ORIENTED PROGRAMMING

Access Modifiers in Python: Underscore Conventions

Lesson Read the full explanation

TL ; DR:

  • Python has no public / private keywords. Privacy is signalled by naming convention:

    • name — public, anyone can read/write.
    • _name — "internal", treat as private (the underscore is a hint to other programmers).
    • __name — name-mangled to _ClassName__name to avoid subclass collisions.

  • Nothing actually stops outside code from reading obj._name. The convention is enforced socially, not by the runtime.



Full lesson:

In Java/C#/C++, the language stops you from reading a private field. In Python, the philosophy is "we're all consenting adults" — the language assumes you read the docs and respect the prefix.


The convention

class Dog:
    def __init__(self, name):
        self._name = name      # "private by convention"

    def get_name(self):
        return self._name

Outside code could still write rex._name, but it shouldn't — the underscore signals "internal, may change without notice".


Your task

The Dog constructor stores the name as self._name. Add a get_name(self) method that returns it.

Dog's name: Rex
STEP 1 OF 2
    Ctrl + Enter to check

    PYTHON · OBJECT-ORIENTED PROGRAMMING

    Access Modifiers in Python, explained

    No private keyword

    Languages such as Java, C# and C++ have public and private keywords, and the compiler refuses to let outside code touch a private field. Python has no such keywords. Its philosophy is that programmers are adults: the language trusts you to read the documentation and respect a naming convention. Privacy in Python is a signal to other programmers, not a lock.

    The three naming levels

    • name is public. Anyone can read and write it.
    • _name, with one leading underscore, means "internal". It tells other programmers that the attribute is an implementation detail and may change without notice. Treat it as private.
    • __name, with two leading underscores, triggers name mangling. Python renames it to _ClassName__name inside the class, mainly to stop a subclass from accidentally reusing the same name.

    A single underscore is only a hint

    class Dog:
        def __init__(self, name):
            self._name = name
    
    rex = Dog("Rex")
    print(rex._name)
    rex._name = "Max"
    print(rex._name)
    
    Rex
    Max
    

    Python does not stop either line. Nothing in the runtime enforces the underscore. The convention works because people follow it, and because tools and style guides flag code that reaches into another class's underscored names.

    Double underscores rename the attribute

    class Dog:
        def __init__(self, name):
            self.__secret = 1
    
    rex = Dog("Rex")
    print(rex._Dog__secret)
    print(rex.__secret)
    
    1
    AttributeError: 'Dog' object has no attribute '__secret'
    

    The attribute is stored as _Dog__secret, so the plain name is not found. This is not real security: anyone who knows the pattern can still reach it. Its purpose is avoiding collisions. If a parent class and its subclass both use __x, they get _Parent__x and _Child__x and do not overwrite each other. For ordinary "please do not touch this" intent, a single underscore is what Python code uses.

    The same convention applies to methods

    Underscores are not only for attributes. A method named _helper tells readers that it supports the class internally and is not part of what outside code should call. The reader learns what is safe to depend on from the names alone.

    Giving access through a method

    When an attribute is marked internal, the class usually offers a method to read it. That keeps outside code on a stable interface, so the class can later change how the value is stored without breaking callers:

    class Dog:
        def __init__(self, name):
            self._name = name
    
        def get_name(self):
            return self._name
    

    Python also has a built-in tool for this, the @property decorator, which lets a method be read like an attribute. A property with no setter even rejects assignment with an AttributeError. That is a topic for later; the exercise here uses a plain method.

    The lesson's exercise

    The starter code gives Dog a constructor that stores the name as self._name, and ends by printing "Dog's name: " joined with rex.get_name(). The class lacks the getter.

    1. Declare the method. Inside the class, at the same level as __init__, write def get_name(self):. Do not forget self.
    2. Return the attribute. In the body, write return self._name. The underscore is part of the name: the attribute was stored as _name, and self.name would not exist.
    class Dog:
        def __init__(self, name):
            self._name = name
    
        def get_name(self):
            return self._name
    
    rex = Dog("Rex")
    print("Dog's name: " + rex.get_name())
    
    Dog's name: Rex
    

    The method uses return, not print. The caller builds a longer message from the value, which only works if the method gives the name back.

    Common mistakes

    • Reading self.name when the attribute is _name. They are different names, and the first raises AttributeError.
    • Expecting the underscore to block access. It does not. Code that writes to an underscored attribute from outside runs fine, and may break later when the class changes.
    • Using double underscores for everyday privacy. Mangling makes testing and debugging harder, and it is meant for avoiding clashes between classes.

    Key takeaways

    • Python has no public or private keywords. Privacy is a naming convention.
    • A leading underscore means "internal, do not rely on it". The runtime does not enforce it.
    • A double leading underscore mangles the name to _ClassName__name to avoid clashes with subclasses.
    • A getter method such as get_name gives outside code a stable way to read an internal attribute.
    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free