Programming with Objects

OOP Encapsulation

Part 2 of the Paper 4 OOP chapter — private attributes (the __ prefix / PRIVATE keyword), getters that return values, setters that update and validate them, and the heart of encapsulation: hiding data so outside code can only reach it through controlled methods. Ends with a full exam-style Member class with mark scheme.

21.1 Introduction to Encapsulation

On Part 1 every attribute was public — any code could read or change it directly. That is risky: nothing stops a careless line from setting a bank balance to a negative number. Real programs protect their data.

The fix is encapsulation: make the attributes private so outside code cannot touch them directly, then provide getter and setter methods as the only doorway in and out. The setter can check a value before storing it. By the end of this page you will hide data, read it with getters, update it with setters, and reject invalid values.

What this page covers
  • Private attributes, encapsulation, getters and setters.
  • The public-class basics are on Part 1 (OOP Classes); inheritance is on Part 4.
TermMeaning
EncapsulationKeeping an object’s data and methods together in one class and hiding the data from outside code. Like a sealed capsule — you use it through buttons, not by reaching inside.
Private attributeAn attribute that can only be used inside its own class. In Python a __ prefix makes it private; in pseudocode the keyword is PRIVATE.
PublicA member that any code can access. In pseudocode PUBLIC; methods are usually public.
GetterA method that returns the value of a private attribute, e.g. get_balance().
SetterA method that updates a private attribute, often after checking the new value is valid.
ValidationA check inside the setter that rejects values which do not make sense (e.g. a negative balance).

21.2 Private Attributes & Encapsulation

Why are we doing this?
  • Mark scheme: Public attributes let any line of code change an object's data with no checks — that is how bugs and bad data creep in.
  • Making attributes private seals them inside the class so the only way to change them is through methods you control.
  • Cambridge expects you to know what encapsulation is and to write private attributes in Paper 4 answers.
Exam tip:
  • Examiner focus: Defining encapsulation was examined in 9618/32 O/N 2022 Q10(a) [3].
  • The same paper asked candidates to complete an object diagram with getters and setters.
  • In Paper 4, 9618/42 O/N 2021 Q2(a) required a class with private attributes [5].

In Python you make an attribute private by putting two underscores in front of its name: self.__balance. Code outside the class then cannot read or change __balance directly — it must go through a method. In Cambridge pseudocode you write the keyword PRIVATE in front of the declaration.

class BankAccount:
    def __init__(self, holder, balance):
        self.__holder  = holder    # private attribute
        self.__balance = balance   # private attribute

The pseudocode equivalent uses the keyword PRIVATE:

CLASS BankAccount
    PRIVATE Holder : STRING
    PRIVATE Balance : REAL
    PUBLIC PROCEDURE NEW(GivenHolder : STRING, GivenBalance : REAL)
        Holder  <- GivenHolder
        Balance <- GivenBalance
    ENDPROCEDURE
ENDCLASS

BankAccount — outside code reaches private data only through public methods

BankAccount

🔒 PRIVATE (hidden)

__holder, __balance

PUBLIC (the doorway)

get_balance()

set_balance()

deposit() withdraw()

👤 Outside code (the user)

Outside code reaches the private data only through the public methods — that is encapsulation.

Key rule
  • Make attributes private (__name in Python, PRIVATE in pseudocode) and expose them only through public getter and setter methods.
  • This is encapsulation.
Exam tip:
  • For the definition of encapsulation, examiners want the two ideas together: data and methods are bundled inside a class, and the data is hidden from outside code.
  • Giving only one half often scores only part of the mark.

21.3 Getter and Setter Methods

Why are we doing this?
  • Once data is private, you need a safe way in and out.
  • A getter hands the value back; a setter changes it.
  • Writing these methods is a routine Paper 4 task, and the names (get_x, set_x) make your code self-explanatory to the examiner.
Exam tip:
  • Examiner focus: Writing get methods was examined directly in 9618/42 O/N 2021 Q2(b) [3].
  • The definitions of getter and setter come straight from the mark scheme of 9618/32 O/N 2022 Q10(a): a getter returns a property; a setter updates a property.

A getter is a method that simply returns the private attribute. A setter takes a new value as a parameter and assigns it. Both reach the private attribute through self. from inside the class — which is allowed, because private only blocks access from outside.

class Person:
    def __init__(self, name, age):
        self.__name = name   # private
        self.__age  = age    # private

    def get_name(self):            # getter
        return self.__name

    def set_name(self, new_name):  # setter
        self.__name = new_name

# usage
person = Person("Mehrin", 16)
print(person.get_name())   # Mehrin
person.set_name("Nazifa")
print(person.get_name())   # Nazifa
Task — Worked Example — get_age and set_age [3 marks]
Write program code (AO3). A Person class has a private attribute __age. Write a getter get_age and a setter set_age. [3]
Hint:
  • Step 1 — getter: return the private attribute (return self.__age).
  • Step 2 — setter: take a parameter and assign it to the attribute (self.__age = new_age).
Your Turn — Your Turn — get_battery_level and set_battery_level [3 marks]
Write program code (AO3). A Laptop class has a private attribute __battery_level. Write a getter get_battery_level and a setter set_battery_level. [3]
Hint:
  • Mirror the Person example exactly.
Key rule
  • A getter uses return to hand a value back.
  • A setter takes the new value as a parameter and assigns it with self..
  • Both work from inside the class, where private access is allowed.
Exam tip:
  • Forgetting return in a getter is the most common slip — without it the method hands back None.
  • The examiner is checking for return self.__attribute exactly.

21.4 Validation Inside the Setter

Why are we doing this?
  • The real power of a setter is that it can refuse a bad value.
  • A balance should never go negative; a battery level should stay between 0 and 100.
  • Putting the check inside the setter means the rule is enforced in one place, no matter who calls it — exactly the protection encapsulation promises.

Add an if inside the setter. If the value is valid, store it; otherwise leave the attribute unchanged and report the problem. The same idea powers deposit and withdraw methods, which validate before changing the balance.

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

    def get_balance(self):
        return self.__balance

    def set_balance(self, amount):
        if amount >= 0:                     # validate first
            self.__balance = amount         # store second
        else:
            print("Balance cannot be negative.")

    def withdraw(self, amount):
        if amount <= self.__balance:
            self.__balance = self.__balance - amount
        else:
            print("Invalid withdrawal amount.")
Task — Worked Example 20.1.8B — set_fuel_level (0 to 100)
Write a setter set_fuel_level for a Car that only accepts a value between 0 and 100.
Hint:
  • The range check guards the attribute on every call: if 0 <= level <= 100.
Your Turn — Your Turn 20.1.8B — set_battery_level (0 to 100)
Write a setter set_battery_level for a Laptop that only accepts a value between 0 and 100.
Hint:
  • Same range guard as the Car.
Key rule
  • A setter should validate first, store second.
  • If the new value breaks a rule, leave the attribute unchanged and report it — never store a value you know is invalid.
Exam tip:
  • When a question says “ensuring the balance does not become negative”, the mark is for the check (if amount >= 0), not just the assignment.
  • Show the condition explicitly.

21.5 Full Exam-Style Question

Paper 4 · OOP · ~12 marks
  • A school library tracks how many books each member currently has on loan.
  • A member must never hold more than five books.

(a) Define the term encapsulation. [2]

(b)(i) Write program code to declare a class Member with a constructor that takes the member's name and sets the number of books on loan to 0. Use private attributes; in Python declare each with a comment. [4]

(b)(ii) Write a getter get_books_out that returns the number of books on loan. [2]

(c) Write a method borrow() that adds 1 to the books on loan, but outputs "Limit reached" and makes no change if the member already has 5. [4]

Lab Task — Show full solution & mark scheme
Reveal the model solution and mark scheme for parts (a)–(c).
Hint:
  • (a) two ideas: bundling data + methods in one class, AND hiding data from outside code.
  • (b)(i) class header; constructor with self + name; private __name set; private __books_out set to 0 (with comments).
  • (b)(ii) get_books_out(self) returns self.__books_out.
  • (c) check if already at 5; output “Limit reached” with no change; else add 1; store back into private attribute.

Key Points Summary

Encapsulation has two parts: (1) bundle data and methods together inside one class, and (2) hide the data from outside code. Examiners want both ideas together — giving only one half scores part marks.
Make attributes private so outside code cannot touch them directly; provide public getter and setter methods as the only doorway in and out.
In Python, a __ prefix (two underscores) makes an attribute private: self.__balance. Outside code cannot read or change it directly.
In Cambridge pseudocode, the keyword PRIVATE in front of the declaration makes an attribute private: PRIVATE Balance : REAL.
Methods are usually declared PUBLIC so outside code can call them — they are the controlled doorway to the hidden data.
A getter returns the value of a private attribute: def get_balance(self): return self.__balance.
A setter updates a private attribute, often after checking the new value: def set_balance(self, amount): self.__balance = amount.
Getters and setters reach private attributes through self. from INSIDE the class — private only blocks access from OUTSIDE.
Standard naming: get_x returns the value of __x; set_x updates __x. The names make your code self-explanatory to the examiner.
Forgetting return in a getter means the method hands back None — the examiner checks for return self.__attribute exactly.
A setter should validate first, store second. If the new value breaks a rule, leave the attribute unchanged and report the problem — never store an invalid value.
Validation lives inside the setter so the rule is enforced in one place, no matter who calls it. This is the protection encapsulation promises.
When a question says "ensuring the balance does not become negative", the mark is for the check (if amount >= 0), not just the assignment.
The same validation idea powers deposit and withdraw methods, which check before changing the balance.
In Python OOP answers, declare each private attribute with a comment (e.g. # private: member name) so the examiner can see your design.

21.6 Practice Tasks

Fifteen exam-style tasks. Click Hint for bullet-point guidance, then Help to reveal a worked Python solution.

1Practice Task — Define encapsulation [2 marks]
Define the term encapsulation.
2Practice Task — Make attributes private [3 marks]
A class Product has public attributes name and price. Rewrite the constructor so both attributes are private. Declare each with a comment.
3Practice Task — Write a getter [2 marks]
A Score class has a private attribute __points. Write a getter get_points that returns it.
4Practice Task — Write a setter (no validation) [2 marks]
A Score class has a private attribute __points. Write a setter set_points that takes a value and assigns it.
5Practice Task — Write a getter and setter pair [3 marks]
A Thermostat class has a private attribute __temperature. Write a getter get_temperature and a setter set_temperature.
6Practice Task — Validation: non-negative balance [3 marks]
A BankAccount class has a private attribute __balance. Write a setter set_balance that only accepts non-negative values.
7Practice Task — Validation: range check (0-100) [3 marks]
A Battery class has a private attribute __level. Write a setter set_level that only accepts values between 0 and 100 inclusive.
8Practice Task — Validation: withdraw with check [4 marks]
A BankAccount class has a private attribute __balance. Write a method withdraw(amount) that subtracts amount only if amount <= balance; otherwise prints an error.
9Practice Task — Full class with private + getter + setter [6 marks]
Write a class Light with a private attribute __brightness (starts at 0). Write a getter get_brightness, and a setter set_brightness that only accepts 0-100.
10Practice Task — Why private not public? [2 marks]
Explain one reason to make an attribute private rather than public.
11Practice Task — Spot the bug: missing return [2 marks]
This getter does not work. Why? `def get_name(self): self.__name`
12Practice Task — Spot the bug: public attribute [2 marks]
A student wrote self.balance = balance in the constructor. Why should this be private, and what is the fix?
13Practice Task — Write a full encapsulated class [8 marks]
Write a class Counter with a private attribute __count (starts at 0). Write get_count, set_count (rejects negative values), and increment() that adds 1.
14Practice Task — Pseudocode private class [4 marks]
In Cambridge pseudocode, declare a class Sensor with a private attribute Reading : REAL, a public constructor NEW that takes a reading, and a public function GetReading that returns it.
15Practice Task — Exam-style: Student with limit [9 marks]
Write a class Student with private __name and __credits (starts 0). Write get_credits, and add_credits(n) that adds n but outputs "Max reached" and makes no change if credits + n > 120.

Question Bank

Answer all questions, then press Submit Quiz to see your score.

0/12 answered

Question 1Multiple Choice

Encapsulation means:

Question 2Multiple Choice

In Python, what prefix makes an attribute private?

Question 3True / False

In pseudocode, the keyword PRIVATE in front of a declaration makes an attribute private.

Question 4Multiple Choice

A getter is a method that:

Question 5Multiple Choice

A setter is a method that:

Question 6Multiple Choice

Why make attributes private instead of public?

Question 7True / False

A getter must use return to hand a value back.

Question 8Multiple Choice

Where should validation for an attribute live?

Question 9Multiple Choice

What should a setter do if the new value is invalid?

Question 10Multiple Choice

For "Define encapsulation", examiners want:

Question 11Multiple Choice

How does a getter reach a private attribute?

Question 12True / False

A setter should validate first, store second.

Answer all 12 questions to enable submission.