← All lessons  ·  Cambridge 9618 A Level · Unit 20.1 · Paper 4 Practical

Object-Oriented Programming
Home Lesson 3 — Using Objects

Work through this page, then build a whole club of members in Python and submit the Evidence Document on Teams.

Home lesson 3 of 6 Language: Python (console) Suggested time: 60 minutes Submit: Evidence Document (.docx)

Start here

How this lesson works

Same routine. This page teaches, then makes you type — and this week your one Member becomes a whole club of them.

  1. Learn on this page. Predict, run, investigate, modify. Nothing to install.
  2. Open your Lesson 2 code. The Member class does not change this week — everything new happens outside it. If your Lesson 2 class is not working, there is a version in the task section to start from.
  3. Evidence it. Paste your code as text and your screenshot into this week's Evidence Document, and submit it on Teams.

Why this lesson matters more than the last two

In the two most recent November examiner reports, Cambridge put this in its Key Messages: candidates can now declare a class well — the marks are being lost at the point where they have to create objects, store them, and work with them through their methods. That is this lesson. Lessons 1 and 2 built the class; this one uses it.


Retrieval

Do Now — three minutes, no notes

Answer these before you read anything else. Write them in your book, then reveal the answers and mark them.

Questions

  1. A student writes this get method: def GetAge(self, Age): return self.__Age. Identify the error and write the corrected method header. [2]
  2. A set method must add Amount to an attribute and never let it go above a limit. State the three steps, in the correct order. [1]
  3. State the output of this code, and explain why the range ends at 3 when the last index is 2. [2]
    Scores = [12, 7, 15]
    Total = 0
    for Index in range(0, 3):
        Total = Total + Scores[Index]
    print(Total)
Mark scheme — mark your own answers
QAcceptedMarks
1MP1 — a get method must not take a parameter (other than self).
MP2 — def GetAge(self):
2
2Add, then limit the new total, then store it. All three, in that order.1
3MP1 — 34
MP2 — the end value of range is not included / range stops one before its end value, so it must be one greater than the last index.
2

Q3 is the prerequisite check. Every loop in this lesson walks through an array by index. An off-by-one range either misses the last object or crashes past the end — examiners report it in seven of the last ten series.


Where this is going

Learning objectives

By the end of this lesson I can…SyllabusPaper
Declare an array of objects with its type evidenced, and store a new object in each element.20.14
Call a method on one element of the array, and on every element using a loop.20.14
Use the values that methods return to total, compare and search — comparing the right thing.20.14
Write a linear search over an array of objects that returns the index, or -1 only after every element has been checked.20.12 & 4

Vocabulary

Key terms — learn these wordings

TermDefinition that earns the mark
Array of objectsAn array whose elements are each an object of the same class. Its data type is that class — ARRAY[0:4] OF Member.
ElementOne position in an array, identified by its index.
IndexThe number that identifies an element's position. In Python the first index is 0.
Linear searchChecks each element in turn, from the first, until the item is found or every element has been checked.
Return valueThe value a function or method passes back to the point where it was called.

What will not earn the mark

"An array of objects is a list of classes" — no mark; the elements are objects (instances), not classes. "A linear search looks through the array" — incomplete; say it checks each element in turn and says when it stops.


PRIMM · Step 1

Predict

Read this program carefully. Do not run it yet. Write down exactly what you think the three print lines will output.

Python — Paper 4
class Book:
    def __init__(self, Title, Pages):
        self.__Title = Title        # STRING
        self.__Pages = Pages        # INTEGER

    def GetTitle(self):
        return self.__Title

    def GetPages(self):
        return self.__Pages

Shelf = [None] * 3                  # ARRAY[0:2] OF Book
Shelf[0] = Book("Dune", 412)
Shelf[1] = Book("Emma", 474)
Shelf[2] = Book("Holes", 233)

print(Shelf[1].GetTitle())
Longest = Shelf[0]
for Index in range(1, 3):
    if Shelf[Index].GetPages() > Longest.GetPages():
        Longest = Shelf[Index]
print(Longest.GetTitle() + " " + str(Longest.GetPages()))
print(Shelf[2])

Commit your prediction before you scroll

Two harder questions: is Longest a number, a title, or something else? And why does the loop start at 1, not 0?


PRIMM · Step 2

Run

Now run it and compare the real output with your prediction.

Python 3 — try it Python is loading…
Output
Press Run to execute.

Your code and your prediction are saved in this browser, so closing the tab does not lose them. If a program never finishes, press Stop.

Check your prediction
Emma
Emma 474
<__main__.Book object at 0x…>
  • Shelf[1].GetTitle() reads left to right: take the array, pick element 1, call its method. Element 1 is the second book, because indexes start at 0.
  • Longest is a whole Book object, not a number and not a title. It starts as the first book and is replaced whenever a longer one turns up. Because it is an object, you can call its methods — Longest.GetTitle() — after the loop. The loop starts at 1 because element 0 is already in Longest; there is no point comparing it with itself.
  • The last line prints the object itself, and Python has no idea how you want a book shown, so you get its type and memory address. An object is not its data. To output what is inside it, call a method: a get method, or a Display… method. Printing a whole object or list instead of the values inside it is a recurring output error in the examiner reports.

Try this — then read why it matters

Add this line to the bottom and run it again:

print(Shelf.GetTitle())

It crashes: 'list' object has no attribute 'GetTitle'. Shelf is the whole array — a list of books — and a list does not have a GetTitle method. Only a book does. You must pick an element first, then call the method on it.


PRIMM · Step 3

Investigate — arrays of objects

1. Declaring the array — and showing its type

Shelf = [None] * 3                  # ARRAY[0:2] OF Book
Shelf[0] = Book("Dune", 412)

[None] * 3 makes an array of three empty elements; each one then has a new object stored in it. The comment does the same job as last week's # STRING: Python cannot declare the type, so you show the examiner that this is an array of type Book. Building it with Shelf = [] and Shelf.append(Book(...)) works just as well — keep the comment either way.

2. Array, then element, then method

You writeWhat happens
Shelf[1].GetTitle()✓ Element 1's title is returned.
Shelf.GetTitle()✗ Crash — the list has no such method.
Shelf[3].GetTitle()✗ IndexError — a three-element array ends at index 2.
GetTitle(Shelf[1])✗ Crash — a method is not a free-standing procedure; it is called on an object with a dot.

3. Looping over every element

for Index in range(0, 3):         # pseudocode: FOR Index ← 0 TO 2
    print(Shelf[Index].GetTitle())

The loop variable is the index, so Shelf[Index] is the object for this pass. The end of the range is one greater than the last index. When a question gives you FOR Index ← 0 TO 4, Python needs range(0, 5).

4. Using what comes back — four patterns

Almost every Paper 4 OOP question asks for one of these. Each one calls a get method on every element and does something with the value returned.

PatternThe shape of it
TotalTotal = 0 before the loop; Total = Total + Shelf[Index].GetPages() inside it; use Total after it.
CountCount = 0 before; if Shelf[Index].GetPages() > 400: Count = Count + 1 inside.
Best so farStart with the first object; replace it whenever an element beats it — the Predict program.
SearchCompare each element's value with the target; return Index the moment it matches; return -1 only after the loop.

5. Compare the value, not the object

Shelf[Index] == "Dune" never crashes and is never true: it compares a whole Book object with a string. You want Shelf[Index].GetTitle() == "Dune". Comparing the wrong thing — the index instead of the element, or the whole object instead of one field — is reported in six of the last ten series, and it is nasty because the program runs and simply never finds anything.

Checkpoint 1

Shelf holds three Book objects. Which line outputs the title of the third book?

Checkpoint 2

Inside a loop, which condition is true when the book at Index is called Emma?


PRIMM · Step 4

Modify

Go back to the runner. Keep the class and the three books, and replace everything from print(Shelf[1]… downwards.

Changes to make

  1. Write a function TotalPages() that returns the total number of pages of all the books in Shelf.
  2. Write a function FindBook(SearchTitle) that returns the index of the book with that title, or -1 if it is not on the shelf.
  3. In the main program, output Total pages: 1119 using TotalPages().
  4. Search for "Holes" and output Holes is at index 2. Then search for "Beloved" and output Beloved is not on the shelf. Store what FindBook returns before you test it.
Model answer — check yours against this
Python — Paper 4
def TotalPages():
    Total = 0
    for Index in range(0, 3):
        Total = Total + Shelf[Index].GetPages()
    return Total

def FindBook(SearchTitle):
    for Index in range(0, 3):
        if Shelf[Index].GetTitle() == SearchTitle:
            return Index
    return -1

print("Total pages: " + str(TotalPages()))

Position = FindBook("Holes")
if Position == -1:
    print("Holes is not on the shelf")
else:
    print("Holes is at index " + str(Position))

Position = FindBook("Beloved")
if Position == -1:
    print("Beloved is not on the shelf")
else:
    print("Beloved is at index " + str(Position))
  • The functions go outside the class — they work with books, they are not part of one. They can read Shelf because it is declared in the main program.
  • In FindBook, return -1 is lined up with the for, not the if. It runs only once the loop has checked every book.
  • Position = FindBook(...) calls the search once and keeps the answer. Writing if FindBook("Holes") != -1: and then calling FindBook again inside the if does all the work twice — and when a call changes something, calling it twice is a real bug that examiners report in five series.

The marks

Exam technique — where the lines go matters

With loops and returns, a line of code in the wrong place — inside the loop instead of before or after it — turns a correct idea into a wrong answer that still runs.

Predict, then reveal. The question says: "Write a function AveragePages() that returns the average number of pages of the three books in Shelf." A candidate writes this. It runs, and returns 137.33…. The right answer is 373.0. Find every fault before you open the answer.

Candidate response
def AveragePages():
    for Index in range(0, 2):
        Total = 0
        Total = Total + Shelf[Index].GetPages()
        return Total / 3
What the examiner says
  • ✗ range(0, 2) misses the last book. It visits indexes 0 and 1 only. Three books need range(0, 3).
  • ✗ Total = 0 is inside the loop. It is reset on every pass, so it can never hold more than one book's pages. Initialise once, before the loop.
  • ✗ return is inside the loop. The function hands back its answer after the first book and stops — the loop never gets a second pass. That is why the answer is 412 ÷ 3.
  • ✓ Shelf[Index].GetPages() — array, element, method, and the returned value is used. That line is credited.
What would have scored
def AveragePages():
    Total = 0
    for Index in range(0, 3):
        Total = Total + Shelf[Index].GetPages()
    return Total / 3

The habit to build: for every line in a loop question, ask "once, or every time?" Setting up a total happens once — before. Adding to it happens every time — inside. Returning the answer happens once — after. The indentation of that line is your answer to the question.

Checkpoint 3

Using the same three books (Dune, Emma, Holes), what does this function return for FindBook("Holes")?

def FindBook(SearchTitle):
    for Index in range(0, 3):
        if Shelf[Index].GetTitle() == SearchTitle:
            return Index
        else:
            return -1


Assessed work

Over to you — build the whole club

Everyone starts at Independent. Drop to Scaffolded if you stall. Go to Exam Conditions when you have finished.

The scenario

The sports club now stores all of its members in one array. The class Member is unchanged from Lesson 2 — constructor, DisplayDetails(), GetName(), GetCredits(), SetAge() and AddCredits(), with credits limited to 50.

IdentifierData typeDescription
ClubMembersARRAY[0:4] OF MemberStores the five members of the club.
IndexMemberIDNameAgeCredits to add
0"M4021""Sara Ahmed"1620
1"M4022""Omar Khalid"1745
2"M4023""Lina Haddad"1660
3"M4024""Yusuf Rahman"180
4"M4025""Mia Chen"1735
SubroutineDescription
TotalCredits()A function that returns the total credits of all the members in ClubMembers.
FindMember(SearchName)A function that returns the index of the member whose name matches SearchName. If no member matches, it returns -1.
Lesson 2 class not working? Start from this version
class Member:
    def __init__(self, MemberID, Name, Age):
        self.__MemberID = MemberID   # STRING
        self.__Name = Name           # STRING
        self.__Age = Age             # INTEGER
        self.__Credits = 0           # INTEGER
        self.__Active = True         # BOOLEAN

    def DisplayDetails(self):
        print("Member ID : " + self.__MemberID)
        print("Name      : " + self.__Name)
        print("Age       : " + str(self.__Age))
        print("Credits   : " + str(self.__Credits))
        print("Active    : " + str(self.__Active))

    def GetName(self):
        return self.__Name

    def GetCredits(self):
        return self.__Credits

    def SetAge(self, NewAge):
        self.__Age = NewAge

    def AddCredits(self, Amount):
        NewTotal = self.__Credits + Amount
        if NewTotal > 50:
            NewTotal = 50
        self.__Credits = NewTotal
Independent — start here

(a) Write program code to declare the array ClubMembers, store a Member object in each element using the test data, and add each member's credits using AddCredits(). [3]

(b) Write program code for the function TotalCredits(). [3]

(c) Write program code for the function FindMember(). [4]

(d) Write a main program that:

  • outputs the total credits, using TotalCredits(), with a label
  • searches for "Lina Haddad" and, if she is found, calls DisplayDetails() on her object
  • searches for "Tom Reilly" and outputs Tom Reilly not found. [3]

(e) Take a screenshot showing the program running. It must show the test data and the complete output. [2]

Scaffolded — only if you stall

Same questions, same marks. Put this below your Member class and complete every ______ and # ....

def TotalCredits():
    Total = ______                            # once, before the loop
    for Index in range(______, ______):
        Total = Total + ClubMembers[Index].______()
    return ______                             # once, after the loop

def FindMember(SearchName):
    for Index in range(0, 5):
        if ClubMembers[Index].______() == SearchName:
            return ______
    # ... what goes here, lined up with the for?

ClubMembers = [None] * 5                  # ARRAY[0:4] OF Member
ClubMembers[0] = Member("M4021", "Sara Ahmed", 16)
# ... elements 1 to 4
StartCredits = [20, 45, 60, 0, 35]
for Index in range(0, 5):
    ClubMembers[Index].______(StartCredits[Index])

print("Total credits: " + str(______))
Position = FindMember("Lina Haddad")
# ... if Position is not -1, call DisplayDetails on ClubMembers[Position]
# ... then the same for "Tom Reilly", outputting "Tom Reilly not found"
Exam conditions — where you need to be by the mock

Close this page. Set a timer for 25 minutes and work from the scenario box alone. Then, as an extension, write this function:

SubroutineDescription
HighestCredits()A function that returns the Member object with the most credits.

At the end of your main program, call it once, store the object it returns, and use that object's get methods to output Most credits: Lina Haddad (50). Think carefully about what your "best so far" should start as.

Before you screenshot

  • Your total should be 150, not 160. Lina's 60 credits are limited to 50 by AddCredits — if you see 160, your Lesson 2 limit is in the wrong place.
  • If FindMember cannot find Lina, check that you compare the name returned by GetName(), not the object — and that return -1 is not in an else.
  • The screenshot must show the test data as well as the output — the lines of code that create the five members, alongside the console.
  • Your code goes into the document as text, never as a screenshot.

Self-marking

Mark scheme — open it only after you have attempted the task

Mark your own work honestly against this, then record your total in the Evidence Document.

Reveal the mark scheme [15 marks]
PointDescriptionMarks
(a) MP1ClubMembers declared with five elements, and its type evidenced as an array of Member (a comment is accepted).1
(a) MP2A Member object created with the correct test data and stored in each of the five elements, in index order.1
(a) MP3AddCredits() called on each element with that member's credits.1
(b) MP4Total initialised to 0 before a loop that visits all five elements.1
(b) MP5GetCredits() called on each element and the value returned added to the total.1
(b) MP6Total returned, after the loop has finished.1
(c) MP7Function takes SearchName as a parameter and loops through the elements.1
(c) MP8…compares the value returned by GetName() for each element with SearchName — not the object itself.1
(c) MP9Returns the index when a match is found.1
(c) MP10Returns -1 only after every element has been checked.1
(d) MP11TotalCredits() called and the value returned output with a label.1
(d) MP12FindMember() called, its result stored, and then tested against -1.1
(d) MP13DisplayDetails() called on the element at the returned index; not-found message output for Tom Reilly.1
(e) MP14Screenshot shows the test data being used, as well as the output.1
(e) MP15Output shows 150, Lina Haddad's details with 50 credits, and Tom Reilly not found.1

Accepted alternatives

  • MP1–MP2: building the array with ClubMembers = [] and append, as long as the type is evidenced and the order matches the indexes.
  • MP3: five separate AddCredits calls, or a loop over a second array of credit values.
  • MP4: for Index in range(0, 5) or range(5). Looping with for M in ClubMembers: is accepted for (b), but (c) must return an index, so it needs one.

Not credited, however good the code looks

  • A loop of range(0, 4) — MP4 lost; Mia is never counted.
  • Total = 0 or return inside the loop — MP4 or MP6 lost.
  • if ClubMembers[Index] == SearchName — MP8 lost, and nothing is ever found.
  • return -1 in an else inside the loop — MP10 lost; only the first member can be found.
  • print(ClubMembers[2]) instead of calling DisplayDetails() — MP13 lost.
  • Code pasted as an image — no code marks at all.

Extension — not counted in the 15

  • E1 "Best so far" starts as the first element (ClubMembers[0]), not as 0 or an empty value.
  • E2 …compares GetCredits() of each remaining element with the best so far, and replaces it when greater.
  • E3 Returns the object, after the loop.
  • E4 Called once; the returned object is stored and its get methods produce Most credits: Lina Haddad (50).

Hand-in

What to submit on Teams

One file: the Evidence Document for this lesson, saved as .docx and named Surname Initial — OOP Home Lesson 3.docx.

Checklist before you upload

  • Your name and class are at the top of the document.
  • Parts (a) to (d) are each pasted as text into their own box, with the indentation intact.
  • Every loop visits all five members, and every return that ends a search or a total sits after the loop.
  • The screenshot shows the test data and the output: total 150, Lina's details, and Tom Reilly not found.
  • Your self-marked total out of 15 is filled in, with the points you lost named.
  • You are submitting the document only — not a zip, not the .py file.

Your next taught lesson opens by checking these submissions. If you got stuck, submit what you have with a note saying where.

Coming next

Home Lesson 4 — Containment or inheritance? What to do when a class design lists another class as one of its attributes — a club that has an array of members. It is the trap Cambridge sets almost every year, and after this week you have already built half of it.

Cambridge 9618 A Level Computer Science  ·  20.1 Programming Paradigms (OOP)  ·  Home Lesson 3 of 6  ·  Paper 4 Practical  ·  United School International