Placement Prep

Encapsulation in Python: Access Modifiers and Name Mangling

Python encapsulation explained: private, protected, public members, name mangling, and getter/setter methods with code examples.

By FACE Prep Team 5 min read
python oops encapsulation placement-prep technical-round python-interview

Encapsulation in Python lets a class own its data. Other code can read or change it only through the methods the class deliberately exposes.

That one-line definition covers the concept. The useful part is understanding how Python implements it, because it doesn’t work the same way Java or C++ does. There are no private or public keywords. The enforcement is by convention and one compiler trick called name mangling. Those details are what interviewers actually test.

What Encapsulation Does in Python

Object-oriented programming gives you four tools: encapsulation, inheritance, polymorphism, and abstraction. Encapsulation is the bundling one. The idea is that a class should own its data and expose only what it needs to expose.

In C++ or Java, private is a hard compile-time restriction. In Python, the language takes a different position: access control is communicated through naming conventions, not enforced by the runtime. The Python documentation on private name mangling states this explicitly: the double-prefix mechanism is primarily intended to avoid name clashes in subclasses, not to create a security boundary.

This distinction matters in interviews. An interviewer who asks “how do you make an attribute private in Python” wants to hear about the __ naming convention and what it does under the hood. An answer of “you just can’t access it” misses the point.

The Three Access Levels: Public, Protected, and Private

Python’s naming convention maps to three levels:

ConventionPrefixScope (by convention)Enforced?
Publicnone (e.g., name)Accessible from anywhereNo
Protectedsingle _ (e.g., _name)Within class and subclassesNo — just a convention
Privatedouble __ (e.g., __name)Class-internal onlyPartially — via name mangling

The “Enforced?” column is the part that trips students up. Protected attributes with a single _ prefix are accessible from outside the class. Python does not block you. The _ prefix signals to other developers: “this is an internal detail, please don’t depend on it.”

Here is a quick demonstration:

class Department:
    def __init__(self):
        self.public_name = "CSE"       # public
        self._record_count = 450       # protected by convention
        self.__internal_id = "D001"    # private — triggers name mangling

All three attributes exist and are accessible from the object. But __internal_id gets renamed by the Python compiler before execution.

Name Mangling: How Python Hides Private Attributes

Name mangling is the one actual mechanism Python provides. Any identifier inside a class body that starts with two or more _ characters and ends with at most one _ gets renamed to _ClassName__identifier at compile time.

So self.__balance inside a class BankAccount becomes self._BankAccount__balance in the compiled bytecode.

The practical effect: if you try to access obj.__balance from outside the class, Python looks for an attribute literally named __balance on the object. No such attribute exists (it was renamed), so you get an AttributeError. The attribute is still there, just under the mangled name.

class BankAccount:
    def __init__(self, opening_balance):
        self.__balance = opening_balance   # stored as _BankAccount__balance

    def get_balance(self):
        return self.__balance              # works: inside the class, mangling applies

account = BankAccount(5000)

# Direct access from outside raises AttributeError
# print(account.__balance)   # AttributeError: 'BankAccount' object has no attribute '__balance'

# Mangled name still works — useful for debugging, not for production code
print(account._BankAccount__balance)   # 5000

Worth stating clearly: name mangling is not encryption. Anyone can access _BankAccount__balance if they know the class name. Python’s PEP 8 naming guide is explicit that the __ prefix exists to prevent accidental overrides in subclass hierarchies, not to enforce secrecy.

Why This Matters for Subclasses

Suppose SavingsAccount extends BankAccount and defines its own __balance. Without mangling, the subclass attribute would silently overwrite the parent’s. Name mangling prevents that collision: the parent’s __balance is stored as _BankAccount__balance, the child’s as _SavingsAccount__balance. Both coexist.

Getter and Setter Methods

Controlling how outside code reads or modifies a private attribute is the core use case for encapsulation in production code. Two approaches exist:

Explicit get/set methods

class Rectangle:
    def __init__(self, length, breadth):
        self.__length = length
        self.__breadth = breadth

    def get_length(self):
        return self.__length

    def set_length(self, value):
        if value <= 0:
            raise ValueError("Length must be positive")
        self.__length = value

    def area(self):
        return self.__length * self.__breadth

rect = Rectangle(5, 3)
print(rect.get_length())   # 5
rect.set_length(8)
print(rect.area())         # 24

The validation in set_length is the practical reason to use a setter rather than exposing __length directly. You can add constraints, logging, or type checks in one place.

The @property Decorator

Python’s idiomatic approach wraps the same logic in a cleaner interface:

class Rectangle:
    def __init__(self, length, breadth):
        self.__length = length
        self.__breadth = breadth

    @property
    def length(self):
        return self.__length

    @length.setter
    def length(self, value):
        if value <= 0:
            raise ValueError("Length must be positive")
        self.__length = value

    def area(self):
        return self.__length * self.__breadth

rect = Rectangle(5, 3)
print(rect.length)   # 5 — accessed like an attribute, not a method call
rect.length = 8      # triggers the setter with validation
print(rect.area())   # 24

The caller writes rect.length instead of rect.get_length(). The interface looks like a plain attribute, but the setter runs validation on every write. This is the preferred style in Python codebases and in placement technical interviews at companies that test Python OOP.

Encapsulation in Placement Technical Rounds

OOP questions (including encapsulation) appear in the technical interview round and in some online assessment platforms’ coding sections. The patterns that come up most are:

  • Write a class with a private attribute and a getter/setter. The expected answer uses the __ naming convention, a validation condition in the setter, and (bonus points) @property.
  • Explain what happens if you access obj.__attr from outside the class. Expected answer: AttributeError, because name mangling renamed it to _ClassName__attr.
  • Difference between _attr and __attr. Expected answer: single _ is a convention with no enforcement; double __ triggers name mangling.
  • Can you still access a name-mangled attribute? Expected answer: yes, via obj._ClassName__attr — Python doesn’t encrypt it.

Students who pair a solid OOP answer with a working code example stand out. A class with private members, a @property getter, and one validation condition in the setter is about 15 lines of code and covers all four patterns above.

For the rest of the technical interview, OOP questions usually appear alongside data structures questions. The 20 most-asked data structures interview questions guide covers arrays, trees, and graphs with the same format: concept, code, complexity, and what the interviewer is actually testing.

A solid next step after practising encapsulation is wrapping a common algorithm in a class. The find smallest and largest element in an array problem is short enough to extend into a clean OOP demonstration with private storage and @property-based access in under 20 lines.

The @property pattern (exposing a clean attribute interface while running validation and type checks internally) is exactly the kind of pattern TinkerLLM’s Python exercises reinforce when building AI tool integrations. If you want to extend this OOP practice into something deployable, TinkerLLM starts at ₹299 and uses the same build-a-class, test-it, ship-it loop.

Primary sources

Frequently asked questions

What is the difference between private and protected in Python?

Private members use a double `__` prefix and trigger name mangling, making naive external access raise AttributeError. Protected members use a single `_` prefix and are accessible from anywhere — the single prefix is a convention asking callers not to touch it, not a runtime lock.

Does Python actually enforce access control like Java or C++?

No. Python has no runtime access control. Single-prefix names are accessible everywhere; double-prefix names are accessible via the mangled form _ClassName__attr. The convention exists to communicate intent to other developers, not to prevent access.

What is name mangling in Python?

Name mangling is Python's compile-time renaming of any identifier with two leading `_` characters (and at most one trailing one) inside a class body. __balance becomes _BankAccount__balance. This prevents accidental overrides in subclasses more than it prevents deliberate access.

How do I create a getter and setter in Python?

Two approaches: explicit methods (def get_balance and def set_balance) or the @property decorator. The @property approach is idiomatic Python because it lets you access the value as an attribute (account.balance) while still running validation logic under the hood.

Why does Python use conventions instead of hard access control?

Python's design philosophy is 'we are all consenting adults here'. Restricting access by convention keeps the language simpler and gives developers the flexibility to inspect or patch objects when they have a legitimate reason, such as debugging or testing.

When do placement interviewers ask encapsulation questions?

Most often in the technical interview round, not the online test. Companies testing OOP knowledge ask you to write a class with private members, explain name mangling, or convert explicit getters/setters to @property. Wipro NLP test technical section and product-company written rounds are the most common settings.

Build AI projects

A self-paced playground for building with LLMs.

TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.

Try TinkerLLM (₹299 launch)
Free AI Roadmap PDF