Home/Learn/Python A–Z/Encapsulation — @property, Underscore Conventions & Name Mangling

Encapsulation — @property, Underscore Conventions & Name Mangling

Intermediate
OOP

Python replaces getters/setters with @property — attribute syntax with method control — and replaces private keywords with conventions: _protected and __mangled.

Overview

Python has no private keyword; it has agreements. A single leading underscore (_balance) means "internal — do not touch from outside" (convention only). A double underscore (__balance) triggers name mangling — the attribute is renamed to _ClassName__balance, preventing accidental override in subclasses (still not true privacy). The crown jewel is @property: expose an attribute publicly, then later add validation or computation behind it WITHOUT changing any caller — the reason Python code skips Java-style getX/setX entirely.

@property — Computed & Validated Attributes

Start with a plain attribute. Need validation later? Convert to a property — callers keep writing obj.attr. The setter runs your checks; a property without a setter is read-only.

Attribute syntax outside, control inside
class Account:
    def __init__(self, balance):
        self._balance = balance          # internal storage

    @property
    def balance(self):                   # read: acc.balance
        return self._balance

    @balance.setter
    def balance(self, value):            # write: acc.balance = x
        if value < 0:
            raise ValueError("balance cannot be negative")
        self._balance = value

    @property
    def balance_lakh(self):              # computed, read-only
        return round(self._balance / 1_00_000, 2)

acc = Account(2_50_000)
print(acc.balance)        # 250000 — attribute syntax, method behind it
acc.balance = 3_00_000    # setter validates
print(acc.balance_lakh)   # 3.0
# acc.balance = -5        # ValueError
# acc.balance_lakh = 9    # AttributeError — no setter

Underscores: _convention vs __mangling

One underscore is a social contract (linters warn, language allows). Two underscores rename the attribute per-class — useful to keep a base-class internal safe from subclass name collisions.

Name mangling protects against subclass collisions
class Engine:
    def __init__(self):
        self._temp = 90          # "internal" — please don't touch
        self.__serial = "X99"    # mangled -> _Engine__serial

e = Engine()
print(e._temp)               # 90 — allowed, but it's on you
# print(e.__serial)          # AttributeError!
print(e._Engine__serial)     # X99 — mangling is renaming, not security

class TurboEngine(Engine):
    def __init__(self):
        super().__init__()
        self.__serial = "T55"   # becomes _TurboEngine__serial — no clash!

t = TurboEngine()
print(t._Engine__serial, t._TurboEngine__serial)   # X99 T55

Key Points to Remember

  • 1No private keyword — _name is convention, __name is name-mangled to _Class__name
  • 2@property lets you start with plain attributes and add logic later without breaking callers
  • 3Property without a setter = read-only attribute
  • 4Never write Java-style get_x()/set_x() in Python — reviewers will flag it

Interview Questions

Sign in to ask Aria
1

How does Python implement encapsulation without private/protected keywords?

MediumCapgemini
2

What is name mangling, what problem does it solve, and why is it not security?

MediumPhonePe
3

Why are @property-based APIs better than getter/setter methods?

MediumAtlassian

Ask Aria about Encapsulation — @property, Underscore Conventions & Name Mangling

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…