← Python

OOP – Private Attributes (underscore convention)

Prefixing an attribute with _ signals it is private and should not be accessed directly from outside the class

What it does: A single underscore is a convention meaning 'do not access directly'. Getters provide controlled read access to private attributes. _name signals 'treat this as private' — Python won't stop you accessing it though. __name becomes _ClassName__name — Python mangles it to make accidental access harder. A setter can check that a new value is valid before storing it. A getter method reads a private attribute safely without exposing it directly. Hiding attributes forces callers to use your methods, where you can validate changes. Python allows it technically — the underscore is just a warning not to do it.

Common mistakes: Directly setting _balance bypasses validation. Use deposit() method. __balance is name-mangled. Access through a getter method.

Class: _____________________  ·  Name: _____________________  ·  Date: _________

Free printable worksheet with full answer key — or add this module to a journey and assign it to your class.

Take this worksheet further — free with Cloodit

Each concept is reinforced from every angle — learned, then applied, then tested.

Learning
Duo
What does a single underscore _ prefix mean?
Convention: internal use, don't access directlyThe variable is deleted
Matches
❌ obj.__balance
Error: Double underscore triggers name mangling
Applying
Meanings
Term
_variable
Meaning
Convention for internal use - don't access directly from outside the class.
Practice
class BankAccount:
Testing
Gaps
def (self, bal):
Check Answer
Spots
1acc = BankAccount(100)
2acc._balance = -500

Cloodit turns curriculum-aligned coding content into journeys students work through one biome at a time.

The 'Space Rabbit' badge — Launch Pad, one of Cloodit's 106 collectible badges
Students earn collectable badges

Over 100 of them, across seven natural biomes.

Study Buddy
Students build a real study resource

Turns their work into revision material ready for Flash Cards and Exam study.

Diamond Dash — one of Cloodit's live, competitive Sprint games
Students lock in with Sprints

Live, competitive practice for the start of the lesson or a teacher-led lesson finisher.

A Cloodit certificate of achievement, ready to personalise and print
Custom printable certificates

Honour your top performers, or encourage a student who's trying hard — ready to print in seconds.

Quick Questions

1. What does a single underscore _ prefix mean?
A. Convention: internal use, don't access directly ✓
B. The variable is deleted
_name signals 'treat this as private' — Python won't stop you accessing it though
2. Does Python enforce single-underscore privacy?
A. Yes you can't access it
B. No it's just a convention ✓
Single underscore is a naming convention only — nothing prevents external access
3. What does double underscore __ do?
A. Name mangling makes it harder to access ✓
B. Deletes the variable
__name becomes _ClassName__name — Python mangles it to make accidental access harder
4. Why use getters and setters?
A. They're faster
B. To control and validate access to attributes ✓
A setter can check that a new value is valid before storing it
5. def get_balance(self): what is this?
A. A getter method that returns the balance ✓
B. A constructor
A getter method reads a private attribute safely without exposing it directly

Match the Pairs

obj.__balance Error: Double underscore triggers name mangling
def getBalance(self): Error: Use snake_case: get_balance
self._balance Valid: Single underscore signals internal use
def get_balance(self): Ok: Getter method to access private data
10 // 3 Output: 3
10 % 3 Output: 1

Key Term

_variable
Convention for internal use - don't access directly from outside the class.~~__variable

Fill in the Blanks

1. class Account: def __init__(self, bal): self._balance = bal
2. class Account: def get_balance(self): return self._balance
3. class Account: def deposit(self, amount): if amount > 0: self._balance += amount
4. class Secret: def __init__(self, val): self.__val = val
5. acc = Account(100) print(acc.get_balance( ))

Spot the Error

Question 1
A acc = BankAccount(100)
B acc._balance = -500
C print(acc.get_balance())
Line B — Directly setting _balance bypasses validation. Use deposit() method.
Question 2
A class Account:
B def __init__(self, bal):
C self.__balance = bal
D
E acc = Account(100)
F print(acc.__balance)
Line F — __balance is name-mangled. Access through a getter method.
Question 3
A class Account:
B def deposit(self, amount):
C self._balance += amount
Line C — No validation should reject negative deposits
Question 4
A class Person:
B def __init__(self, age):
C self._age = age
D def set_age(self, age):
E self._age = age
Line E — Setter has no validation should check age > 0
Question 5
A class Account:
B def __init__(self, bal):
C self._balance = bal
D def get_balance():
E return self._balance
Line D — Missing self parameter in get_balance method
For Teachers

Create a free class, add this module to a journey, and track who's stuck.

Create a free teacher account →

No credit card. No setup fee. Make a class and invite students in under three minutes.

For Students

Practice this topic interactively, track progress, and unlock badges.

Start Learning Free →

Have a class code?