Learning

Encapsulation & Access Control

Encapsulation & Access Control

Public Members

python
class User: def __init__(self, name): self.name = name # Public — accessible anywhere u = User('Alice') print(u.name) # 'Alice' u.name = 'Bob' # Direct modification — no restrictions

Protected Members (_prefix)

python
class BankAccount: def __init__(self, balance): self._balance = balance # Protected by convention def _validate(self, amount): # Protected method return amount > 0 # _balance is STILL accessible — it's just a CONVENTION acc = BankAccount(1000) print(acc._balance) # 1000 (works, but you shouldn't!) acc._balance = -500 # Works, but violates the convention

Private Members (__prefix) & Name Mangling

python
class Secret: def __init__(self): self.__hidden = 'secret data' def get_hidden(self): return self.__hidden s = Secret() # print(s.__hidden) # AttributeError! print(s.get_hidden()) # 'secret data' # Name mangling: __hidden becomes _Secret__hidden print(s._Secret__hidden) # 'secret data' (works but DON'T do this!)

Getter & Setter Methods

python
class Temperature: def __init__(self, celsius): self.__celsius = celsius def get_celsius(self): return self.__celsius def set_celsius(self, value): if value < -273.15: raise ValueError('Below absolute zero!') self.__celsius = value t = Temperature(25) t.set_celsius(30) print(t.get_celsius()) # 30 # t.set_celsius(-300) # ValueError!

Why Python's 'Private' Isn't Truly Private

python
class Parent: def __init__(self): self.__value = 'parent' class Child(Parent): def try_access(self): # self.__value looks for _Child__value, NOT _Parent__value! # return self.__value # AttributeError! return self._Parent__value # Works with mangled name c = Child() print(c.try_access()) # 'parent'
Key Rules
  • •Public (no prefix): accessible everywhere — use for attributes that form the object's public API
  • •Protected (_prefix): convention only, NOT enforced — signals 'internal use, subclass may access'
  • •Private (__prefix): name-mangled to _ClassName__attr — prevents accidental access, not security
  • •Name mangling uses the CLASS where the attribute is defined, not the class accessing it
  • •Use getter/setter methods when you need validation — but prefer @property for Pythonic code (next topic)
Your Task

Create a `BankAccount` class with `__balance` (private), `_transaction_log` (protected), and `owner` (public). Add `deposit(amount)` and `withdraw(amount)` methods that validate amount > 0 and update `__balance`. Add `get_balance()` getter. Show that `__balance` can't be accessed directly but `_transaction_log` can (with a warning comment). Demonstrate valid and invalid operations.

EditorPython · JSX
PreviewUpdates on Run Tests
Loading preview…
Tests
Should define BankAccount with __balance
Should define _transaction_log (protected)
Should have public owner attribute
Should have deposit method with validation
Should have withdraw with balance check
Should demonstrate private access error