Lesson 80 +10 XP

Encapsulation and Inner Classes

Encapsulation and Inner Classes

Encapsulation hides an object's internal data. Inner classes are classes defined inside other classes.

Private attributes with _

A single underscore is a convention meaning "keep it internal":

class MyClass:
    def __init__(self):
        self._protected = "don't touch"

Stronger privacy with __

Double underscores trigger name mangling, making the attribute harder to reach from outside:

class MyClass:
    def __init__(self):
        self.__private = "secret"

obj = MyClass()
print(obj.__private)  # AttributeError

It's still reachable as obj._MyClass__private, so it's a warning, not a wall.

Encapsulation via methods

Expose data through methods instead of direct access:

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance

    def get_balance(self):
        return self.__balance

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount

Getters and setters

@property gives a clean, attribute-like interface:

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

Inner classes

A class can live inside another class:

class Outer:
    class Inner:
        def method(self):
            print("Inner method")

Use the dot chain to reach it:

obj = Outer.Inner()
obj.method()  # Inner method

Why inner classes?

They group closely related classes and limit their visibility.

TL;DR

  • Single _ is a convention; double __ triggers name mangling.
  • Encapsulation exposes data through methods.
  • @property creates clean getters/setters.
  • Inner classes live inside another class.