Python Encapsulation

Let’s look at encapsulation

  1. Notice

    A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

  2. Try

    Follow the example, change its sample, and compare what happens.

  3. Check

    Explain the result and test your understanding.

Watch how it works

Focus on how the names, objects, and calculations change. We’ll inspect the printed output in the next section.

Explore the idea

Follow the code and watch its state change. Guided simulation.

Code
Python
class Account:
    def __init__(self):
        self._balance = 0
    def deposit(self, amount):
        self._balance += amount
    def balance(self):
        return self._balance
account = Account()
account.deposit(3)
print(account.balance())
Live state

Top-level scope

Account→Object 3
account→Object 4
Object 3 · typeclass AccountObject 4 · AccountAccount({'_balance': 3})
This step

A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

Picture encapsulation

A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

Image brief

Alt text
A diagram for Python Encapsulation. Instructions: class Account: def __init__(self): self._balance = 0 def deposit(self, amount): self._balance += amount def balance(self): return self._balance account = Account() account.deposit(3) print(account.balance()). Displayed result: 3. The final example bindings are Account --> object 3 (type); account --> object 4 (Account). object 3: class Account; object 4: Account({'_balance': 3})
Image generation prompt
Create a clean educational illustration for a Python programming lesson titled "Python Encapsulation". Teaching focus: A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them. Depict exactly the relationships and labels in this reference diagram: EXAMPLE INSTRUCTIONS class Account: def __init__(self): self._balance = 0 def deposit(self, amount): self._balance += amount def balance(self): return self._balance account = Account() account.deposit(3) print(account.balance()) | v DISPLAYED RESULT 3 FINAL BINDINGS Account --> object 3 (type) account --> object 4 (Account) object 3: class Account object 4: Account({'_balance': 3}) Use a flat vector style, generous spacing, clear arrows and legible labels, with a restrained blue/teal palette on a plain background. The diagram must explain the programming idea accurately. Do not depict variables as boxes containing copied objects when they share a reference. Avoid mascots, decorative screenshots, logos, gradients and extra text. Landscape composition, approximately 3:2, suitable for a course card. Accessible description: A diagram for Python Encapsulation. Instructions: class Account: def __init__(self): self._balance = 0 def deposit(self, amount): self._balance += amount def balance(self): return self._balance account = Account() account.deposit(3) print(account.balance()). Displayed result: 3. The final example bindings are Account --> object 3 (type); account --> object 4 (Account). object 3: class Account; object 4: Account({'_balance': 3})

Follow the execution

Choose a different sample input, then follow every step through to the output. Before revealing it, predict what the program will display.

Execution workspace

Choose a sample and follow its execution. Guided simulation.

Code
Python
class Account:
    def __init__(self):
        self._balance = 0
    def deposit(self, amount):
        self._balance += amount
    def balance(self):
        return self._balance
account = Account()
account.deposit(3)
print(account.balance())
Live state

Top-level scope

Account→Object 3
account→Object 4
Object 3 · typeclass AccountObject 4 · AccountAccount({'_balance': 3})
This step

The example has finished. Compare the final output with the values and references above.

Terminal
Output
3

What do you expect this program to print?

What does this example display?

class Account:
    def __init__(self):
        self._balance = 0
    def deposit(self, amount):
        self._balance += amount
    def balance(self):
        return self._balance
account = Account()
account.deposit(3)
print(account.balance())
What does this example display?
Choose one answer. You can try again.

Answer and explanation

3

Follow the printed values in order. The output is: 3

Which explanation matches what you learned?

Which explanation matches what you learned?
Choose one answer. You can try again.

Answer and explanation

A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

More examples and reference

In the real world, we keep some things private or protected — like your phone password or your bank PIN. In Python, we can also keep some data inside a class private using a concept called encapsulation.

Encapsulation means hiding the details of how something works and only showing what's necessary. This helps keep things safe and organized.

Why Use Encapsulation?

  • To protect important data inside a class.
  • To control how the data is accessed or changed.
  • To avoid mistakes or misuse of data from outside the class.

Simple Example Without Encapsulation

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

person = Person("Arjun", 25)
print(person.name)  # OK
print(person.age)   # OK

person.age = -10    # ❌ Invalid age, but Python allows it!
print(person.age)

Output

Arjun
25
-10

What's the Problem?

We allowed someone to set age to -10, which doesn't make sense. We need a way to protect this value.

Encapsulation Using Private Variables

We can make variables private by using two underscores __ in front of the variable name. This tells Python: "Don’t let anyone access this directly."

class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age  # Private variable

    def get_age(self):
        return self.__age

    def set_age(self, new_age):
        if new_age > 0:
            self.__age = new_age
        else:
            print("Age must be positive.")

person = Person("Arjun", 30)
print(person.name)           # OK
print(person.get_age())      # OK

person.set_age(-5)           # Not allowed
print(person.get_age())      # Still 30

Output

Arjun
30
Age must be positive.
30

Explanation

  • __age is a private variable – it cannot be accessed directly from outside.
  • get_age() is a method to read the age.
  • set_age() is a method to change the age — but only if it’s valid!

Trying to Access Private Variable Directly

print(person.__age)

Output

AttributeError: 'Person' object has no attribute '__age'

This error happens because __age is private. Python doesn’t allow direct access.

Conclusion

Encapsulation helps keep your data safe. You hide it using private variables and provide special methods to read or change the data — this gives you full control and avoids mistakes.

What to remember

Connect what you noticed in the example with the idea below.

Remember

A leading underscore signals an internal attribute by convention. Encapsulation exposes useful operations while keeping implementation details behind them.

Watch out for this idea

A leading underscore makes an attribute completely inaccessible.

This is the misconception to avoid.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Python Polymorphism →