Interactive exercises, quizzes and guided lessons covering all 18 programming topics in AQA specification 8525, Section 3.2. Designed for students in Years 10 and 11 (ages 14–16).
This platform provides free, interactive Python revision for students preparing for the AQA GCSE Computer Science examination (specification 8525, often called AQA GCSE CS or simply the AQA Computer Science exam). Every lesson is mapped directly to Section 3.2 of the official AQA specification, so you can revise with confidence that you are covering exactly what the examiners expect.
Each of the 18 topic units on this site combines several exercise types: multiple-choice questions to test recall, fill-in-the-blank exercises to practise syntax, code-writing challenges where you write Python from scratch with live feedback, and bug-fixing tasks where you identify and correct errors in provided code. As you work through the exercises you earn experience points (XP), unlock achievement badges, and maintain a daily learning streak — all without needing to create an account, because your progress is saved locally in your browser.
The site is completely free. It is designed for students in Years 10 and 11 (typically ages 14–16) studying for their GCSEs, but it is also used by teachers who want to point students to quick practice resources, and by older students who are brushing up on Python fundamentals. Whether you are just starting to learn Python or preparing for your final exams, the structured progression through all 18 topics will help you build both understanding and exam technique.
All written content on this site is original and produced independently. This site is not affiliated with, endorsed by, or connected to AQA in any way. AQA specification references are used solely to help students identify which topics they need to study.
Variables and data types are the absolute foundation of every Python program. Before you can write meaningful code, you need to understand how data is stored and labelled in memory, and what kinds of data Python can work with.
A variable is a named location in memory used to store a value that your program can read and change as it runs. Think of it like a labelled box: the label is the variable name, and whatever is inside the box is the value. When you write score = 0, you are telling Python to create a box called score and put the number 0 inside it. Later in the program, you can change what is in the box — for example, score = score + 10 increases the value by ten.
A constant is similar, but its value is intended to remain the same throughout the entire program. The speed of light, the maximum number of login attempts, the price of a subscription — these are all good candidates for constants because changing them by accident would cause serious bugs. Python does not actually prevent you from changing a constant (unlike some other languages), but the convention of writing constants in UPPER_CASE is a clear signal to anyone reading the code. AQA examiners expect students to understand this distinction and to use UPPER_CASE for constants in exam answers.
AQA GCSE Computer Science requires knowledge of exactly four data types. You must be able to identify, declare, and use all four:
int) — whole numbers, positive or negative, with no decimal point. Examples: 42, -7, 0, 1000000. Used for things like scores, counts, ages, and index positions.float) — numbers that include a decimal point. AQA uses the term "real" rather than "float" — use this terminology in written exam answers. Examples: 3.14, -0.5, 99.9. Note that 10.0 is a real number even though it looks like a whole number, because it has a decimal point.bool) — can only hold one of two values: True or False. These must be capitalised in Python. Booleans are commonly used as flags — for example, is_logged_in = False starts as false and is set to True once the user provides correct credentials.str) — any sequence of characters enclosed in quotes, either single ('hello') or double ("hello"). A string can contain letters, digits, spaces, punctuation, or even nothing at all (an empty string: ""). Python does not have a separate character type — a single character is simply a string of length one.score = 0 # integer variable — stores a whole number MAX_LIVES = 3 # integer constant — UPPER_CASE by convention pi = 3.14159 # real (float) variable temperature = -12.5 # real (float) — negative is fine is_logged_in = False # boolean variable — True or False only username = "Alice" # string variable — text in quotes empty = "" # empty string — valid, length zero # Python infers the type automatically — no need to declare it explicitly print(type(score)) # <class 'int'> print(type(pi)) # <class 'float'> print(type(is_logged_in)) # <class 'bool'> print(type(username)) # <class 'str'>
True and False must start with a capital letter. Writing true, TRUE, or false will cause a NameError. Similarly, forgetting that constants should be UPPER_CASE will cost marks in AQA exam questions that ask you to "identify the constant" in a block of code.
age > 18) is always a Boolean value.
student_name — String, because a name is a sequence of characters.percentage — Real (float), because percentages can include decimal values such as 73.5.has_passed — Boolean, because passing is either True or False.
Almost every useful program needs to communicate with the user — receiving information from them and displaying results back. Python's input() and print() functions are the building blocks of this communication.
print() sends output to the screen (technically to standard output). You can pass it a string directly, a variable, or an expression, and it will display the result followed by a newline. You can print multiple values separated by commas — Python adds a space between them by default. If you want to avoid the automatic newline at the end, you can use the optional end argument: print("Hello", end="").
input() pauses the program and waits for the user to type something and press Enter. The string you pass as an argument is shown as a prompt — the text the user sees before they type. Crucially, input() always returns what the user typed as a string, regardless of what they actually entered. If the user types 42, Python receives the string "42", not the number 42. This is the source of many student mistakes.
# Basic print — concatenation with +
name = "Bob"
print("Hello, " + name + "!") # Hello, Bob!
# print() with comma-separated values
age = 17
print("Name:", name, "Age:", age) # Name: Bob Age: 17
# f-strings (formatted string literals) — the modern, preferred way
print(f"Hello, {name}! You are {age} years old.") # Hello, Bob! You are 17 years old.
# Expressions inside f-strings
price = 4.99
quantity = 3
print(f"Total: £{price * quantity:.2f}") # Total: £14.97
# input() — always returns a string
colour = input("What is your favourite colour? ")
print(f"You chose: {colour}")
input() without converting it first. For example, total = input("Score: ") + 10 will crash with a TypeError because you cannot add a string and an integer. You must cast first: total = int(input("Score: ")) + 10.
input(). AQA mark schemes often award a mark specifically for the prompt. Also, if a question says "the user inputs a number", remember that you must cast the result to int or float — just using input() alone is not enough.
a = float(input("Enter the first number: "))
b = float(input("Enter the second number: "))
print(f"Sum: {a + b}")
print(f"Difference: {a - b}")
print(f"Product: {a * b}")
Python provides a full set of arithmetic operators for mathematical calculations. The standard operators (+, -, *, /) work exactly as you would expect, but two operators in particular — integer division and modulo — are tested heavily in AQA exams and have their own pseudocode equivalents you must know.
Standard arithmetic in Python follows the same precedence rules as in mathematics, often remembered as BIDMAS or BODMAS: Brackets first, then Indices (powers), then Division and Multiplication (left to right), then Addition and Subtraction (left to right). You can always use parentheses to change the order of evaluation.
+ — addition: 3 + 4 → 7- — subtraction: 10 - 6 → 4* — multiplication: 5 * 3 → 15/ — real division: always returns a float, even if the result is a whole number. 10 / 2 → 5.0// — integer division (AQA pseudocode: DIV): divides and drops the remainder, giving a whole number. 10 // 3 → 3% — modulo (AQA pseudocode: MOD): returns only the remainder after integer division. 10 % 3 → 1** — exponentiation (power): 2 ** 8 → 256print(10 + 3) # 13
print(10 - 3) # 7
print(10 * 3) # 30
print(10 / 3) # 3.3333... (real division — result is a float)
print(10 // 3) # 3 (integer division — AQA: 10 DIV 3)
print(10 % 3) # 1 (modulo/remainder — AQA: 10 MOD 3)
print(2 ** 8) # 256 (2 to the power of 8)
# BIDMAS / BODMAS — precedence matters
print(2 + 3 * 4) # 14, not 20 — multiplication before addition
print((2 + 3) * 4) # 20 — brackets override precedence
# Practical use of modulo — check if a number is even or odd
number = int(input("Enter a number: "))
if number % 2 == 0:
print("Even")
else:
print("Odd")
The modulo operator has many practical uses beyond simply finding remainders. You can use it to check whether a number is divisible by another (n % 5 == 0 is true whenever n is a multiple of 5), to wrap an index around the end of a list, or to extract individual digits from a number.
/ (real division) and // (integer division). Remember: 7 / 2 gives 3.5, while 7 // 2 gives 3. Also be careful with mixed types — 7 / 2 always returns a float even when the answer is a whole number. And remember: in AQA pseudocode, integer division is written as DIV and modulo as MOD.
DIV or MOD, remember these translate to // and % in Python.
Selection is one of the three fundamental programming constructs (along with sequence and iteration). It gives a program the ability to make decisions: to do different things depending on the current state of the data. In Python, selection is written using if, elif, and else.
An if statement evaluates a condition — a Boolean expression that is either True or False. If the condition is True, the indented block of code beneath it is executed. If the condition is False, Python skips that block. You can add as many elif (else-if) branches as needed to test additional conditions, and a final else branch will catch anything that did not match any earlier condition.
Indentation is not optional in Python. The indented code block beneath an if statement is what belongs to that condition. AQA examiners mark indentation, so always use consistent 4-space indentation in your exam answers.
grade = int(input("Enter your mark (0–100): "))
if grade >= 90:
print("Grade 9 — Outstanding!")
elif grade >= 80:
print("Grade 7–8 — Excellent work")
elif grade >= 70:
print("Grade 6 — Good")
elif grade >= 60:
print("Grade 5 — Pass")
elif grade >= 50:
print("Grade 4 — Standard pass")
else:
print("Grade 3 or below — Keep practising!")
# Nested if — checking multiple conditions in layers
age = int(input("Enter your age: "))
has_id = input("Do you have ID? (yes/no): ")
if age >= 18:
if has_id == "yes":
print("Entry permitted")
else:
print("Please show valid ID")
else:
print("Sorry, you must be 18 or over")
Relational (comparison) operators used in conditions: == (equal to — note two equals signs, not one), != (not equal to), > (greater than), < (less than), >= (greater than or equal to), <= (less than or equal to).
= instead of double equals == inside an if condition is one of the most frequent mistakes. = assigns a value; == compares two values. Writing if grade = 90: is a syntax error; it must be if grade == 90:.
if grade >= 50 before if grade >= 90, a student who scored 95 will match the first condition and never reach the Grade 9 branch. Work from the highest or most specific condition down to the least specific.
age = int(input("Enter your age: "))
if age < 16:
price = 7
elif age >= 65:
price = 9
else:
price = 12
print(f"Your ticket costs £{price}")
Logical operators allow you to combine multiple conditions into a single expression. AQA requires knowledge of three logical operators: AND, OR, and NOT. In Python, these are written as lowercase keywords: and, or, not.
and — returns True only if both conditions are true. age >= 18 and has_id == True is only true when both requirements are met.or — returns True if at least one condition is true. day == "Saturday" or day == "Sunday" is true on either weekend day.not — inverts a Boolean value. not is_logged_in is True when is_logged_in is False, and vice versa.age = 17
has_pass = True
is_member = False
# AND — both conditions must be true
if age >= 16 and has_pass:
print("Boarding allowed")
# OR — either condition is sufficient
if age < 13 or not has_pass:
print("Entry denied or pass required")
# NOT — negates a condition
if not is_member:
print("Please sign up for a membership")
# Combining all three
if (age >= 18 or is_member) and has_pass:
print("Full access granted")
# Truth table example — print all combinations
for a in [True, False]:
for b in [True, False]:
print(f" {a} AND {b} = {a and b}")
AND, OR, NOT, but in Python these are always lowercase. Exam questions often include a truth table and ask you to write the corresponding condition — practise translating truth tables into Python expressions. Also remember that not has higher precedence than and, which has higher precedence than or. Use brackets to make complex conditions readable.
Iteration — the ability to repeat a block of code — is one of the most powerful features of any programming language. Without loops, you would have to write the same instruction hundreds of times to process a list of data. Python provides two types of loop: for loops (definite iteration) and while loops (indefinite iteration).
A for loop repeats a block of code a known, fixed number of times, or once for each item in a sequence. The most common pattern uses the range() function to generate a sequence of numbers. range(start, stop, step) produces integers from start up to (but not including) stop, incrementing by step each time.
# Count from 1 to 10 inclusive
for i in range(1, 11):
print(i)
# Count down from 10 to 1
for i in range(10, 0, -1):
print(i)
print("Blast off!")
# Iterate over a string — each character in turn
word = "Python"
for char in word:
print(char)
# Iterate over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit.upper())
# range() details:
# range(5) → 0, 1, 2, 3, 4
# range(1, 6) → 1, 2, 3, 4, 5
# range(0, 10, 2) → 0, 2, 4, 6, 8
# range(5, 0, -1) → 5, 4, 3, 2, 1
A while loop keeps repeating as long as its condition remains True. You use it when you do not know in advance how many repetitions will be needed — for example, when validating user input (keep asking until they enter something valid), or when running a game loop (keep playing until the player loses all their lives).
# Keep asking until the user enters a valid password
password = ""
while password != "secret123":
password = input("Enter the password: ")
print("Access granted")
# Input validation — ensure a positive number is entered
score = -1
while score < 0 or score > 100:
score = int(input("Enter a score between 0 and 100: "))
print(f"Valid score recorded: {score}")
# Counter-controlled while loop (equivalent to for loop)
count = 1
while count <= 5:
print(f"Attempt {count}")
count += 1 # don't forget to update the counter!
False. This happens when you forget to update the variable being tested inside the loop. For example, if you wrote while count <= 5: print(count) without count += 1, the program would print forever. Always make sure something inside a while loop will eventually make the condition false.
for loop and a while loop and justify your answer. The rule of thumb: use for when the number of repetitions is known in advance; use while when you are repeating until a condition is met and the number of repetitions is unknown. AQA also sometimes calls these count-controlled (for) and condition-controlled (while) loops.
String handling is one of the most heavily tested topics in AQA GCSE Computer Science. You need to be comfortable with indexing, slicing, concatenation, and a range of built-in string methods.
A string is a sequence of characters stored in order. Each character in a string has an index (position number), starting at 0 for the first character. This zero-based indexing is very important — students who assume the first character is at position 1 will produce wrong answers in trace questions. Python also supports negative indexing: -1 refers to the last character, -2 the second-to-last, and so on.
text = "Python" # Indexing — accessing a single character print(text[0]) # 'P' — first character (index 0) print(text[1]) # 'y' print(text[5]) # 'n' — last character print(text[-1]) # 'n' — last character using negative index print(text[-2]) # 'o' — second from last # Slicing — extracting a substring # text[start:stop] — includes start, excludes stop print(text[0:3]) # 'Pyt' — characters at positions 0, 1, 2 print(text[2:5]) # 'tho' — characters at positions 2, 3, 4 print(text[2:]) # 'thon' — from position 2 to the end print(text[:3]) # 'Pyt' — from the start to position 2
name = " Alice Smith "
print(len("Python")) # 6 — number of characters
print("hello".upper()) # 'HELLO'
print("HELLO".lower()) # 'hello'
print(name.strip()) # 'Alice Smith' — remove whitespace
print("Python".replace("P","J")) # 'Jython'
print("cat,dog,fish".split(",")) # ['cat', 'dog', 'fish']
print("Hello".find("ll")) # 2 — index of 'll', or -1 if not found
# Concatenation — joining strings with +
first = "Ada"
last = "Lovelace"
full = first + " " + last
print(full) # 'Ada Lovelace'
# Checking substrings
sentence = "The quick brown fox"
print("quick" in sentence) # True
print("slow" in sentence) # False
# Iterating over characters
vowels = 0
for char in "Programming":
if char.lower() in "aeiou":
vowels += 1
print(f"Vowel count: {vowels}")
text[2:5], not text[2:4]. A useful trick: the number of characters in a slice is always stop minus start. Also remember: len() gives the total number of characters, so the last valid index is always len(text) - 1.
Type casting (also called type conversion) means converting a value from one data type to another. This is necessary because Python is strongly typed — you cannot, for example, add a string and an integer without first converting one of them.
The three casting functions you need to know for AQA are int(), float(), and str(). Each converts its argument to the specified type if possible, and raises an error if the conversion is impossible (for example, int("hello") will cause a ValueError).
# str → int : only works if the string contains a whole number
age_str = "16"
age = int(age_str) # 16 (integer)
print(age + 1) # 17
# str → float : the string must contain a valid decimal number
price_str = "3.99"
price = float(price_str) # 3.99 (float)
# int / float → str : convert a number to a string for concatenation
score = 95
message = "Your score is: " + str(score)
print(message) # "Your score is: 95"
# Chaining — most common pattern in practice
height = float(input("Enter your height in metres: ")) # e.g. 1.75
weight = float(input("Enter your weight in kg: ")) # e.g. 70
bmi = weight / (height ** 2)
print(f"Your BMI is {bmi:.1f}")
# What CANNOT be cast
# int("hello") → ValueError: invalid literal for int()
# float("true") → ValueError
# int(3.9) → 3 (truncates, does NOT round)
int(3.9) gives 3, not 4. Casting a float to an int truncates (removes the decimal part without rounding). If you need to round, use the built-in round() function: round(3.9) gives 4. Also, casting an integer to a float always succeeds (float(5) → 5.0), but casting a float to an integer loses precision.
A list allows you to store multiple related values in a single variable. Instead of creating student1, student2, student3 as separate variables, you can store them all in a single list. This makes it easy to process large collections of data using loops.
In Python, lists are written using square brackets with items separated by commas: ["apple", "banana", "cherry"]. Items in a list are accessed by their index, starting at 0, just like characters in a string. AQA GCSE Computer Science uses the word array in its pseudocode — in Python, a list serves the same purpose.
scores = [72, 85, 91, 64, 78]
# Accessing items by index
print(scores[0]) # 72 — first item
print(scores[-1]) # 78 — last item
print(len(scores)) # 5 — number of items
# Modifying a list
scores[0] = 75 # update an item
scores.append(88) # add to the end
scores.insert(2, 60) # insert 60 at index 2
scores.remove(64) # remove first occurrence of 64
popped = scores.pop() # remove and return the last item
# Useful list operations
print(sorted(scores)) # return a sorted copy
print(min(scores)) # smallest value
print(max(scores)) # largest value
print(sum(scores)) # total of all values
print(sum(scores)/len(scores)) # calculate the mean
# Iterating over a list with a for loop
names = ["Alice", "Bob", "Charlie"]
for name in names:
print(f"Hello, {name}!")
# Iterating with index using range and len
for i in range(len(scores)):
print(f"Score {i+1}: {scores[i]}")
FOR i <- 0 TO LEN(myArray) - 1. In Python this translates to for i in range(len(my_list)). Also remember: list indices start at 0, so a list with 5 elements has valid indices 0, 1, 2, 3, 4 — accessing index 5 will cause an IndexError.
A 2D list (two-dimensional list) is a list where each item is itself a list. This creates a grid or table structure with rows and columns, making it ideal for storing things like seating arrangements, game boards, spreadsheet data, or a class register with multiple attributes per student.
grid = [
[1, 2, 3], # row 0
[4, 5, 6], # row 1
[7, 8, 9] # row 2
]
# Accessing elements: grid[row][column]
print(grid[0][0]) # 1 — top-left (row 0, col 0)
print(grid[1][2]) # 6 — row 1, column 2
print(grid[2][1]) # 8 — bottom-middle
# Modifying a cell
grid[1][1] = 99
print(grid[1]) # [4, 99, 6]
# Iterating over all cells with a nested for loop
for row in grid:
for cell in row:
print(cell, end=" ")
print() # newline after each row
# 2D list as a class register
register = [
["Alice", "Smith", True],
["Bob", "Jones", False],
["Carol", "White", True]
]
for student in register:
status = "Present" if student[2] else "Absent"
print(f"{student[0]} {student[1]}: {status}")
Functions and procedures allow you to break a large program into smaller, reusable pieces. Instead of repeating the same block of code in multiple places, you define it once as a function and call it whenever needed. This makes programs shorter, easier to read, and easier to maintain.
In AQA Computer Science, there is an important distinction between a function and a procedure: a function always returns a value using the return statement, whereas a procedure performs an action but does not return anything. In Python, both are created with the def keyword. If a Python function does not include a return statement, it implicitly returns None and is acting like a procedure.
# Procedure — performs an action, returns nothing
def display_welcome(name):
print(f"Welcome to the quiz, {name}!")
print("Good luck!")
# Function — calculates and returns a value
def calculate_area(width, height):
area = width * height
return area
# Function — can return different values based on input
def letter_grade(mark):
if mark >= 90:
return "A*"
elif mark >= 80:
return "A"
elif mark >= 70:
return "B"
elif mark >= 60:
return "C"
else:
return "U"
# Calling the subprograms
display_welcome("Alice") # calls the procedure
area = calculate_area(5, 8) # stores the returned value
print(f"Area: {area}") # 40
grade = letter_grade(75)
print(f"Grade: {grade}") # B
# Functions can call other functions
def describe_grade(mark):
grade = letter_grade(mark)
if grade in ["A*", "A"]:
return f"Grade {grade} — Excellent!"
else:
return f"Grade {grade}"
Parameters are the variable names listed inside the parentheses in the function definition — they are like placeholders that receive the data when the function is called. Arguments are the actual values passed when you call a function. These two terms are often confused — remember: parameters are defined, arguments are passed.
def power(base, exponent): # base and exponent are PARAMETERS
result = base ** exponent
return result
answer = power(2, 10) # 2 and 10 are ARGUMENTS
print(answer) # 1024
# A function can return multiple values as a tuple
def min_max(numbers):
return min(numbers), max(numbers)
lo, hi = min_max([5, 3, 8, 1, 9, 2])
print(f"Min: {lo}, Max: {hi}") # Min: 1, Max: 9
# Default parameter values — the argument is optional
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Bob") # Hello, Bob!
greet("Alice", "Hi there") # Hi there, Alice!
Scope determines which parts of the program can "see" and use a variable. A local variable is created inside a function and can only be accessed within that function — it does not exist outside. A global variable is defined outside all functions and can be read from anywhere in the program. However, to modify a global variable from inside a function, you must declare it with the global keyword; otherwise Python creates a new local variable with the same name instead.
total_score = 0 # global variable — exists everywhere
def add_points(points):
global total_score # declares we mean the GLOBAL variable
total_score += points # modifies the global
def show_score():
print(f"Total score: {total_score}") # can READ global without 'global'
add_points(10)
add_points(25)
show_score() # Total score: 35
# Local variable — only exists inside the function
def calculate_discount(price, pct):
discount = price * pct / 100 # 'discount' is LOCAL
return price - discount
final = calculate_discount(100, 20)
# print(discount) # NameError — 'discount' doesn't exist out here
global keyword when you intend to modify a global variable is a subtle bug. The code will not crash — Python will silently create a new local variable with the same name, and the global will remain unchanged. This can be very hard to spot. As a general rule, try to avoid modifying global variables from inside functions; it is better practice to pass values in as parameters and return results.
Saving data to files is essential for any program that needs to persist information between runs — for example, a game that saves high scores, or a system that stores student records. Python makes file handling straightforward with the built-in open() function.
The recommended way to open a file in Python is using a with statement. The with block automatically closes the file when you leave the block, even if an error occurs. This is safer than opening and closing manually, and is the expected style in AQA exam answers.
"r" — read mode (default). Opens the file for reading. Raises an error if the file does not exist."w" — write mode. Creates a new file, or overwrites the existing file completely."a" — append mode. Adds new content to the end of an existing file without deleting what is already there.# Writing to a file (creates or overwrites)
with open("scores.txt", "w") as f:
f.write("Alice: 95\n")
f.write("Bob: 87\n")
f.write("Carol: 91\n")
# Appending — add a new score without losing the others
with open("scores.txt", "a") as f:
f.write("Dave: 78\n")
# Reading the whole file at once
with open("scores.txt", "r") as f:
contents = f.read()
print(contents)
# Reading one line at a time (better for large files)
with open("scores.txt", "r") as f:
for line in f:
line = line.strip() # removes \n at the end
print(line)
# Reading all lines into a list
with open("scores.txt", "r") as f:
lines = f.readlines() # each line is an item in the list
print(f"Number of records: {len(lines)}")
with open(...) as f: pattern. Also remember that when you read from a file, each line includes a newline character (\n) at the end — use .strip() to remove it before processing. When writing, you must explicitly add \n to move to the next line.
Programs do not always run smoothly. A user might type letters when the program expects a number, or a file might not be where the program expects to find it. Without exception handling, these situations cause the program to crash with an unhelpful error message. A try/except block lets you catch errors and respond to them gracefully.
An exception is an error that occurs while the program is running (a runtime error). When an exception occurs inside a try block, Python stops executing the try block and jumps to the matching except block. You can have multiple except clauses to handle different types of exceptions differently.
ValueError — raised when a function receives the right type but an invalid value, e.g. int("hello").ZeroDivisionError — raised when dividing by zero.IndexError — raised when accessing a list with an out-of-range index.FileNotFoundError — raised when trying to open a file that does not exist.TypeError — raised when an operation is applied to the wrong type, e.g. "text" + 5.# Basic try/except
try:
age = int(input("Enter your age: "))
print(f"Next year you will be {age + 1}")
except ValueError:
print("Please enter a whole number, not text.")
# Multiple except clauses
try:
numerator = int(input("Numerator: "))
denominator = int(input("Denominator: "))
result = numerator / denominator
print(f"Result: {result}")
except ValueError:
print("Please enter integers only.")
except ZeroDivisionError:
print("Error: cannot divide by zero.")
# Input validation loop using exceptions
while True:
try:
score = int(input("Enter a score (0–100): "))
if score < 0 or score > 100:
raise ValueError("Score out of range")
break # only reaches here if no exception was raised
except ValueError:
print("Invalid input. Please enter a whole number between 0 and 100.")
print(f"Score recorded: {score}")
Testing is the process of running a program with carefully chosen inputs to verify that it behaves correctly. AQA GCSE Computer Science requires you to understand three categories of test data and three types of programming error.
>= vs >, <= vs <) are written correctly.if statement, unmatched brackets, or a misspelled keyword.int() on a string that does not contain a number.> instead of >=, causing a boundary case to be handled incorrectly.# Test table example — testing a grade classifier
# Function to test:
def classify(score):
if score >= 70:
return "Distinction"
elif score >= 50:
return "Pass"
else:
return "Fail"
# Test cases covering normal, boundary, and erroneous data:
test_cases = [
(75, "Distinction"), # normal — well above boundary
(50, "Pass"), # boundary — exactly at Pass threshold
(70, "Distinction"), # boundary — exactly at Distinction threshold
(69, "Pass"), # boundary — just below Distinction
(49, "Fail"), # boundary — just below Pass
(0, "Fail"), # extreme boundary — minimum possible
(100, "Distinction"), # extreme boundary — maximum possible
]
for score, expected in test_cases:
actual = classify(score)
status = "PASS" if actual == expected else "FAIL"
print(f" classify({score}) = {actual} (expected {expected}) [{status}]")
A dictionary is a collection of key–value pairs. Where a list stores values in numbered positions (index 0, 1, 2 …), a dictionary lets you use any immutable value as a key — typically a string or integer that has meaningful descriptive power. You look up a value by providing its key, not a position number.
Dictionaries are defined using curly braces {} with each key–value pair separated by a colon and pairs separated by commas. They are ideal for storing records where each field has a name — a student's details, a product's attributes, or a telephone directory.
student = {
"name": "Alice",
"age": 16,
"grade": "A",
"passed": True
}
# Accessing values by key
print(student["name"]) # "Alice"
print(student["grade"]) # "A"
# Adding and updating
student["school"] = "St Mary's" # add a new key
student["age"] = 17 # update an existing value
# Removing a key
del student["passed"]
# Check if a key exists
if "name" in student:
print("Name found:", student["name"])
# Iterating over a dictionary
for key, value in student.items():
print(f" {key}: {value}")
# Real-world example — a phone book
contacts = {
"Alice": "07700 900001",
"Bob": "07700 900002",
"Carol": "07700 900003"
}
name = input("Who do you want to call? ")
if name in contacts:
print(f"Number: {contacts[name]}")
else:
print("Contact not found.")
Computer security is an increasingly important topic in GCSE Computer Science. Section 3.2.15 covers how programs protect user accounts and data, including authentication mechanisms, password storage, and common attack types.
Authentication is the process of verifying that someone is who they claim to be. The most common form is username/password authentication, where the user provides credentials that the system checks against its records. A key principle is that passwords should never be stored in plain text — if a database is compromised, plaintext passwords give attackers immediate access to every account, often across multiple sites (since people reuse passwords).
Instead of storing the password itself, a system stores a hash — the output of a one-way mathematical function applied to the password. The same password always produces the same hash, but it is computationally infeasible to work backwards from the hash to the original password. When a user logs in, the system hashes the entered password and compares the hash to the stored one.
import hashlib
def hash_password(password):
# SHA-256 produces a 64-character hex string
return hashlib.sha256(password.encode()).hexdigest()
# Registration — store the hash, not the password
stored_hash = hash_password("mySecret123")
print(f"Stored hash: {stored_hash[:20]}...") # first 20 chars shown
# Login — hash the attempt and compare
attempt = input("Enter password: ")
if hash_password(attempt) == stored_hash:
print("Login successful")
else:
print("Incorrect password")
# Simple login system with attempt limiting
MAX_ATTEMPTS = 3
attempts = 0
while attempts < MAX_ATTEMPTS:
pwd = input("Password: ")
if hash_password(pwd) == stored_hash:
print("Access granted")
break
attempts += 1
remaining = MAX_ATTEMPTS - attempts
if remaining > 0:
print(f"Wrong password. {remaining} attempts remaining.")
else:
print("Account locked after too many failed attempts.")
Having studied all 18 topics, here are the most important exam technique tips based on the most common mark-losing mistakes in AQA Computer Science papers:
int(input(...)), not just input(...), when asking for a number. Forgetting to cast is the single most common error in student code.DIV and MOD — these map to Python's // and %. Know both.text[2:5] gives characters at positions 2, 3, 4 (not 5).for vs while — and be able to justify your choice. Definite iteration (known number of repetitions) → for. Condition-controlled (repeat until something happens) → while.About this site: GCSE Python is a free, independent revision resource for students studying AQA GCSE Computer Science (specification 8525). It is not affiliated with, endorsed by, or in any way connected to AQA. All original content is written and maintained by the site's creator. If you have a question or spot an error, please get in touch. For more information about the site, visit the About page.