← All lessons · Cambridge 9618 A Level · Unit 20.1 · Paper 4 Practical
Work through this page, then add the new methods to your Lesson 1 code in Python and submit the Evidence Document on Teams.
Start here
Same routine as last week. This page teaches, then makes you type — and this week you build on the Member class you wrote in Lesson 1.
Member class. If you did not finish Lesson 1, there is a starting version in the task section — use it rather than stopping.Why a whole lesson on something this small
A get method is two lines long. It is also the single most repeated OOP error in the examiner reports — in all ten of the last ten series. And the idea underneath it, the difference between returning a value and outputting it, is the spine of the whole paper: examiners report marks lost to it in every series, on every question type. Get this right now and it pays on every question you ever write.
Retrieval
Answer these before you read anything else. Write them in your book, then reveal the answers and mark them.
Questions
Points, INTEGER, set to 0 when the object is created." A student's constructor begins def __init__(self, Points):. Explain why this does not follow the design. [1]Total = CalculateTotal(Prices). State whether CalculateTotal is a function or a procedure, and justify your answer. [2]| Q | Accepted | Marks |
|---|---|---|
| 1 | Attributes are declared private so they can only be accessed through the class's own methods. Reject: "hiding the code". | 1 |
| 2 | Points has a fixed starting value, so the constructor should assign 0 itself — it must not be a parameter. | 1 |
| 3 | MP1 — a function. MP2 — because it returns a value, which is assigned to / stored in Total.Reject for MP2: "because it has brackets" / "because it takes a parameter" — procedures do both. | 2 |
Q3 is the prerequisite check. A get method is a function that belongs to a class: it hands a value back to the line that called it. If you said "procedure", reread row 3 before you go on.
Where this is going
| By the end of this lesson I can… | Syllabus | Paper |
|---|---|---|
| Explain the difference between returning a value and outputting it, and tell from the wording of a question which one is required. | 20.1 | 2 & 4 |
Write a get method that takes no parameter other than self and returns a private attribute unchanged. | 20.1 | 4 |
| Write the three kinds of set method that Paper 4 examines: one that replaces, one that adds to, and one that clamps to a limit. | 20.1 | 4 |
| Call a get method on an object and store or use the value it returns. | 20.1 | 4 |
Where this sits in the paper
Almost every Paper 4 OOP question asks for at least one get method and one set method, usually straight after the constructor. They are among the cheapest marks on the paper — and among the most often dropped, because candidates write them from a half-remembered pattern instead of from the rule.
Vocabulary
Written the way a mark scheme writes them. Learn the wording, not the gist.
| Term | Definition that earns the mark |
|---|---|
| Get method (getter, accessor) | A method that returns the value of a private attribute, without changing it. |
| Set method (setter, mutator) | A method that takes a parameter and uses it to assign a new value to a private attribute. |
| Return | To pass a value back to the point in the program from which the function or method was called. |
| Output | To display a value, for example on the screen with print. Outputting a value does not return it. |
| Encapsulation | Attributes are declared private so they can only be accessed through the class's own methods. Get and set methods are those methods. |
What will not earn the mark
"A getter gets the attribute" — no mark; it repeats the word it is defining. "Return means show the answer" — no mark; that is outputting. "A setter changes an attribute" — incomplete; say it takes a parameter and assigns it.
PRIMM · Step 1
Read this program carefully. Do not run it yet. Two methods that look almost identical. Write down exactly what you think the program will output, line by line.
Python — Paper 4class Book: def __init__(self, Title, Year): self.__Title = Title # STRING self.__Year = Year # INTEGER def GetTitle(self): return self.__Title def ShowTitle(self): print(self.__Title) MyBook = Book("Dune", 1965) A = MyBook.GetTitle() B = MyBook.ShowTitle() print("A is", A) print("B is", B)
Commit your prediction before you scroll
Two harder questions while you are here: which line prints the first thing you see? And what do you think is stored in B?
PRIMM · Step 2
Now run it. Press Run and compare the real output with your prediction. Python runs inside this page — nothing is sent anywhere.
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.
Dune A is Dune B is None
A = MyBook.GetTitle() prints nothing. GetTitle hands the title back, and the program quietly stores it in A.Dune on the screen comes from B = MyBook.ShowTitle(). ShowTitle outputs the title — it goes to the screen and is gone.B holds None — Python's word for nothing was returned. ShowTitle never hands anything back, so there is nothing to store. If a question says a method returns the title and you write ShowTitle, the program looks right on screen and still loses the mark, because the calling code gets nothing.Try this — then read why it matters
Add this line to the bottom of the code above and run it again:
MyBook.GetTitle()
Nothing appears. The method ran, returned "Dune", and the program threw it away because nothing stored it or printed it. Not storing or using a returned value is reported in every one of the last ten series. A value that comes back from a call has to go somewhere: into a variable, into a print, or into a calculation.
PRIMM · Step 3
Before you write a method, find the verb in the question or the class design. It is an instruction, not a figure of speech.
| The design says… | So your method… |
|---|---|
| returns the name | ends with return self.__Name. No print anywhere. |
| outputs / displays the name | uses print. Nothing needs to be returned. |
| returns TRUE if…, otherwise FALSE | returns a Boolean on every path through the method — not only when the answer is True. |
def GetYear(self): return self.__Year
self. The object already holds the value; there is nothing to pass in. A get method with a parameter is the most repeated OOP error on Paper 4.return, of the attribute.input, no assignment, no print. A get method that also changes the attribute is not a get method.def SetYear(self, NewYear): self.__Year = NewYear
self — the new value. Not input() inside the method: the value arrives through the parameter.NewYear = self.__Year runs without an error and changes nothing. Read every assignment right-to-left: "take NewYear, put it into Year".Paper 4 does not stop at "replace the value". Two variants come up, and they are where the marks spread out.
Add to — the parameter is an amount to add, not the new value:
def AddPoints(self, Amount): self.__Points = self.__Points + Amount
Writing self.__Points = Amount here throws away everything the object already had. Read the design: "adds Amount to Points" is not "sets Points to Amount".
Clamp — add, but never go past a limit. The order is everything: add first, then limit, then store.
def AddPoints(self, Amount): NewTotal = self.__Points + Amount # 1. add if NewTotal > 100: # 2. limit NewTotal = 100 self.__Points = NewTotal # 3. store
Trace it with Points at 90 and a call of AddPoints(30):
| Order used | Points afterwards | Verdict |
|---|---|---|
| Add, then limit, then store | 100 | ✓ correct |
| Limit the old value, then add | 120 — 90 passes the check, then 30 is added | ✗ |
| Limit the parameter, then add | 120 — 30 is under 100, so nothing happens | ✗ |
Adding straight into the attribute and then correcting it (self.__Points = self.__Points + Amount, then if self.__Points > 100: self.__Points = 100) is also fine — the value left stored is still limited. What matters is that the limit is applied to the new total, after the addition.
The class design says: "GetTitle() returns the title of the book." Which method follows the design?
GetTitle() the right way now gets a crash.self, one return, and the attribute is left unchanged. That is the whole of a get method.None back. The design says "returns".PRIMM · Step 4
Go back to the runner and change the program to do the following.
Changes to make
GetYear() that returns the year.SetYear(NewYear) that replaces the year with the parameter.Book("Dune", 1956), then correct it by calling SetYear(1965).GetTitle() and GetYear() — no direct access to the attributes — output exactly: Dune is 61 years old. Use 2026 as the current year.Step 4 is the one that matters
Examiners now say that declaring classes is a national strength and that the marks are being lost at the point where candidates have to use objects — calling methods and doing something with what comes back. GetYear() returns a number; your program has to catch it and do arithmetic with it. That is exactly the skill.
class Book: def __init__(self, Title, Year): self.__Title = Title # STRING self.__Year = Year # INTEGER def GetTitle(self): return self.__Title def GetYear(self): return self.__Year def SetYear(self, NewYear): self.__Year = NewYear MyBook = Book("Dune", 1956) MyBook.SetYear(1965) Published = MyBook.GetYear() BookAge = 2026 - Published print(MyBook.GetTitle() + " is " + str(BookAge) + " years old")
GetYear() is stored in Published and then used. The value returned by GetTitle() is used directly inside the print. Both are fine.str(BookAge) is needed — joining an integer to a string with + crashes. Using commas in print works on screen too, but get into the + and str() habit: examiners flag strings built with commas elsewhere on the paper, where a comma makes a tuple.ShowTitle() has gone. It was never asked for, and a method that nobody calls is just more to go wrong.An object NewMember has a get method GetName() that returns the member's name. Which line outputs the member's name?
print. Storing it first — Name = NewMember.GetName() then print(Name) — is equally good.AttributeError, and even in a language where it ran, it would defeat the encapsulation the question is testing.NameError. Calling methods as free procedures appears in six of the last ten series — methods are always called on an object, with a dot.The marks
A game stores each player as an object. The design says:
Class design — Player (extract)
| Method | Description |
|---|---|
| GetHealth() | Returns the value of Health. |
| Heal(Amount) | Adds Amount to Health. Health can never be greater than 100; if the new total would be greater than 100, Health is set to 100. |
Predict, then reveal. A candidate writes this. Decide what an examiner would credit before you open the answer.
Candidate responsedef GetHealth(self, Health): print(self.__Health) def Heal(self, Amount): if self.__Health > 100: self.__Health = 100 self.__Health = self.__Health + Amount
Both methods look plausible. Neither earns full marks.
GetHealth takes a parameter. The most repeated OOP error on the paper. The parameter is never even used.GetHealth outputs instead of returning. The design says "returns". Any code that calls it gets None.Heal takes one parameter and adds to Health rather than replacing it. Credited.Heal limits in the wrong order. It checks the old value, then adds. A player on 90 who heals by 30 ends on 120. The limit mark is lost, even though the candidate clearly knew a limit was needed.def GetHealth(self): return self.__Health def Heal(self, Amount): NewHealth = self.__Health + Amount if NewHealth > 100: NewHealth = 100 self.__Health = NewHealth
The habit to build: before you write a method, underline the verb in its description. Returns → return. Outputs → print. Adds → + onto what is already there. Can never be greater than → a limit applied to the new total, after the addition.
The design says: "AddCredits(Amount) adds Amount to Credits. Credits can never be greater than 50." Credits is currently 40. Which method leaves Credits at 50 after AddCredits(25)?
Credits ends on 65.Credits with 25 instead of adding to it. The limit is in the right place, but the design says "adds", so the 40 credits the member already had are lost.Assessed work
Everyone starts at Independent. Drop to Scaffolded if you stall. Go to Exam Conditions when you have finished.
The scenario
The sports club from Lesson 1 now needs to read and update its members' records. The attributes and the constructor are unchanged from Lesson 1. Four new methods are added to the class Member.
| Attribute | Data type | Set when the object is created |
|---|---|---|
| MemberID | STRING | From a parameter |
| Name | STRING | From a parameter |
| Age | INTEGER | From a parameter |
| Credits | INTEGER | Always 0 |
| Active | BOOLEAN | Always True |
| Method | Description |
|---|---|
| Constructor | As Lesson 1. |
| DisplayDetails() | As Lesson 1 — outputs all five attributes, each on its own line, with a label. |
| GetName() | New. Returns the value of Name. |
| GetCredits() | New. Returns the value of Credits. |
| SetAge(NewAge) | New. Assigns the parameter NewAge to Age. |
| AddCredits(Amount) | New. Adds the parameter Amount to Credits. Credits can never be greater than 50; if the new total would be greater than 50, Credits is set to 50. |
Copy this into your editor and add the new methods to it. You still owe the Lesson 1 submission — this is so you are not stuck twice.
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))
(a) Write program code for the get methods GetName() and GetCredits(). [3]
(b) Write program code for the set method SetAge(). [2]
(c) Write program code for the method AddCredits(). [4]
(d) Write a main program that:
Member object using the test data "M4021", "Sara Ahmed", 161730 credits, and then adds 35 creditsSara Ahmed has 50 creditsDisplayDetails(). [3](e) Take a screenshot showing the program running. It must show the test data and the complete output. [2]
Same questions, same marks. Add these to your class and complete every ______ and # .... Do not change anything else.
def GetName(self): return ______ def GetCredits(______): # ... one line def SetAge(self, ______): self.__Age = ______ def AddCredits(self, Amount): NewTotal = ______ + ______ # 1. add # ... 2. limit: if the new total is over 50, make it 50 # ... 3. store the new total in the attribute # ---- main program ---- # ... create the object with the test data, in a variable called TheMember # ... call SetAge on it with 17 # ... call AddCredits twice: 30, then 35 print(TheMember.GetName() + " has " + str(______) + " credits") # ... call DisplayDetails on it
Close this page. Set a timer for 20 minutes. Work from the class design alone. Then, as an extension, add this method and test it:
| Method | Description |
|---|---|
| Spend(Amount) | If Credits is greater than or equal to Amount, subtracts Amount from Credits and returns TRUE. Otherwise leaves Credits unchanged and returns FALSE. |
At the end of your main program, call Spend(20) and then Spend(40) on the same member. After each call, store the value returned and use it to output either Payment accepted or Payment refused. Then output the credits remaining, using GetCredits(). All of it must appear in one screenshot.
Before you screenshot
AddCredits are chosen so that a wrongly-ordered limit shows up as 65 instead of 50.Self-marking
Mark your own work honestly against this, then record your total in the Evidence Document.
| Point | Description | Marks |
|---|---|---|
| (a) MP1 | GetName() and GetCredits() declared as methods of the class, each with no parameter other than self. | 1 |
| (a) MP2 | GetName() returns Name. | 1 |
| (a) MP3 | GetCredits() returns Credits. | 1 |
| (b) MP4 | SetAge() declared with exactly one parameter after self. | 1 |
| (b) MP5 | …parameter assigned to Age — attribute on the left. | 1 |
| (c) MP6 | AddCredits() declared with exactly one parameter after self. | 1 |
| (c) MP7 | Amount added to the existing Credits, not replacing it. | 1 |
| (c) MP8 | A total greater than 50 is set to 50. | 1 |
| (c) MP9 | …the limit is applied to the new total, after the addition, and the result is stored in Credits. | 1 |
| (d) MP10 | Object created with the test data, in a variable not named after the class, and SetAge(17) called on it. | 1 |
| (d) MP11 | AddCredits(30) then AddCredits(35) called on the object, and DisplayDetails() called on it. | 1 |
| (d) MP12 | Message output using the values returned by GetName() and GetCredits() — not by reaching into the attributes. | 1 |
| (e) MP13 | Screenshot shows the test data being used, as well as the output. | 1 |
| (e) MP14 | Output shows Sara Ahmed has 50 credits, and DisplayDetails() shows age 17 and 50 credits. | 1 |
The … at the start of MP5 and MP9 is Cambridge notation: that mark cannot be awarded without the one before it.
Accepted alternatives
self.__Credits = self.__Credits + Amount, then if self.__Credits > 50: self.__Credits = 50). The value left stored is limited, so it is credited.print. Both are accepted.Not credited, however good the code looks
SetAge() that reads input() instead of using its parameter — MP4 and MP5 lost.Extension — not counted in the 14
Spend() compares Credits >= Amount — greater than or equal to.True in that case; returns False otherwise, with Credits unchanged. A Boolean is returned on every path.Result = TheMember.Spend(20) — and then tested. Calling Spend inside the if and again in the body spends the credits twice: a bug examiners report in five series.Payment accepted, then Payment refused, then 30 credits remaining.Hand-in
One file: the Evidence Document for this lesson, saved as .docx and named Surname Initial — OOP Home Lesson 2.docx.
Checklist before you upload
self, and returns — no print inside..py file.Your next taught lesson opens by checking these submissions. If you got stuck, submit what you have with a note saying where — that is far more useful to me than nothing.
Home Lesson 3 — Using objects. Not one member but a whole club: an array of objects, a loop over it, and doing something with every value your get methods hand back. This is the skill examiners currently name as the national weakness on Paper 4, and today's lesson is the foundation for it.