๐ข The print() Function
The print() function is used to output text, numbers, or variables to the screen.
print("hello", "\nworld")
Spacing: You can use a comma , to combine variables, strings, and numbers in
the same print statement. Python automatically adds a space between items separated by a comma.
Concatenation: You can also use the + operator to combine items, but
be careful: you can only concatenate strings with other strings, or add numbers to other
numbers. Mixing them will cause a type error! The benefit of + is that it doesn't add any
spaces automatically.
๐ฆ Variable Assignment
Variables are like boxes that store values. You assign a value to a variable using a single equals sign
=.
# Assigning a number
a = 5
# Assigning text (strings)
a = "hello"
โ Python Operators
Python uses standard symbols to do calculations. Below is your quick reference guide. Click on any example value to evaluate it live in the simulator!
+print(8 + 2)10-print(8 - 2)6*print(8 * 2)16/print(10 / 4)2.5%print(10 % 3)1//print(10 // 4)2**print(10 ** 4)10000* (on text)print("7" * 2)77๐ป Calculations in Python
This program demonstrates how you can combine different operators to perform calculations.
# Assigning values to variables
width = 10
height = 3
# Basic arithmetic
perimeter = (width + height) * 2
area = width * height
# Division, floor division, and modulus
items = 10
people = 3
share = items / people # 3.333... (float division)
even_share = items // people # 3 (integer division)
leftover = items % people # 1 (remainder)
print("Area:", area)
print("Share:", share)
print("Remainder:", leftover)
๐ฅ Read User Inputs
The input() function allows programs to pause and ask the user for information.
# 1. Text Inputs (Default)
name = input("Hi! What's your name? ")
By default, everything entered is treated as Text (a string). You cannot perform
mathematical operations on text, even if the user types in numbers like 123.
# 2. Number Inputs
MyAge = int(input("When were you born? "))
By wrapping input() inside int(), the text input is converted into an **Integer
(a whole number)**, allowing you to calculate values with it.
โฐ Time Delays (time.sleep)
You can create pauses or delays in your code using the time module.
Please note in run mode the entire program runs at once and so you will only see the completed code.
Display mode will not wait for the sleep function.
import time
print("Wait for it...")
time.sleep(2) # Pause for 2 seconds
print("Worth waiting for!")
๐งต F-Strings (Formatted String Literals)
F-strings provide a concise, readable way to format strings in Python. They allow you to embed variables, numbers, and expressions directly inside a string by prefixing it with an f and wrapping the variables or expressions in curly braces {}.
name = "Aisha"
print(f"Hello, {name}!") # Output: Hello, Aisha!
Crucial Rule: Always remember to put the letter f (lowercase or uppercase) right before the opening quote. If you forget the f, Python will treat it as a normal string and print the braces and variable name literally (e.g., "Hello, {name}!").
๐งช Interactive F-String Builder
Experiment with how variables and values are dynamically formatted inside f-strings. Change the values below to see the generated code and output immediately:
# Code will be generated here
โจ Key Features & Course Topics
Here are the key patterns and formatting options for using f-strings, as covered in our F-String Comic Academy course:
You can place multiple variables inside a single f-string to build complete sentences.
hero = "Nova"
city = "Byte City"
power = "lightning"
print(f"{hero} protects {city} using {power}!")
Normally, combining strings and numbers with + causes a TypeError. F-strings handle numbers automatically, without needing to call str().
player = "Pixel"
score = 95
# No need for str(score)!
print(f"{player} scored {score} points!")
Braces can contain simple calculations or operations. Python evaluates them before inserting the result into the string.
coins = 12
bonus = 5
print(f"You now have {coins + bonus} coins.") # Output: You now have 17 coins.
You can run string methods directly inside the braces. This returns a modified copy for display without changing the original variable.
hero = "nova"
print(f"Hero: {hero.upper()}") # Output: Hero: NOVA
Use the format specifier :.2f inside the braces to round and display numbers with exactly two decimal places.
price = 7.5
# :.2f ensures two decimals (ideal for currency)
print(f"Price: ${price:.2f}") # Output: Price: $7.50
Use the format specifier :.1% to multiply a decimal by 100, display one decimal place, and append a percentage sign automatically.
rate = 3 / 4
print(f"Win rate: {rate:.1%}") # Output: Win rate: 75.0%
๐ F-String Comic Academy
Put your knowledge to the test! Learn to master f-strings step-by-step through a series of fun comic missions featuring Byte and Pixel.
๐ก Common Mistakes & Best Practices
Keep these rules in mind to avoid errors in your code:
- Missing the 'f': Writing
"{name} scored {score}!"prints the variable names literally. Always add the leadingfbefore the opening quote. - Quote Nesting: If your f-string uses double quotes, use single quotes inside the braces (and vice-versa) to avoid syntax errors:
print(f"Greeting: {user['name']}") - Keep it Clean: Only use f-strings when you have variables or expressions to insert. For fixed text, plain strings are faster and clearer. Avoid putting complex logic in braces; compute it first and store in a variable.
๐ Selection: If & Else
Selection allows programs to make decisions and execute different blocks of code depending on conditions.
test = input("Is it raining? y/n ")
if test == "y":
print("Oh dear, no football today!")
else:
print("Great, let's go and play football!")
๐ Elif (Else If)
Use elif when you need to check multiple conditions sequentially. Once a condition is met, the
subsequent checks are skipped.
age = 18
if age < 17:
print("You are not old enough to drive or vote.")
elif age == 17:
print("You are old enough to drive!")
else:
print("You are old enough to drive and vote!")
๐ง Quick Quiz: Selection
Given this code block, what will it print if the user inputs 18?
age = int(input("Age: "))
if age >= 17:
print("Drive!")
elif age >= 18:
print("Vote!")
else:
print("Wait!")
๐ Iteration: While Loops
Loops allow computers to repeat instructions quickly. A while loop repeats as long as a
condition is true.
love_status = "y"
while love_status == "y":
love_status = input('Do you love iteration? y/n ')
๐ The Break Statement
You can end a loop instantly using the break statement, even if the loop condition is still
true.
while True:
user_input = input("Enter Q to quit: ")
if user_input == "Q":
break
๐ For Loops & range()
A for loop repeats a set number of times. You can use range() to customize the
loop sequence.
# 1. Repeat 20 times (0 to 19)
for i in range(20):
print(i)
# 2. Start, Stop, and Steps
# Goes from 1 to 99 in steps of 2 (stops before 100)
for i in range(1, 100, 2):
print(i)
๐ String Length: len()
The len() function returns the number of characters in a string.
greeting = "Good Day!"
print(len(greeting)) # Outputs: 9
๐ Logical Operator: or
Use the or operator to check if at least one of multiple statements is true.
number = 0
while number < 15 or number > 20:
print("Please enter a number between 15 and 20")
number = int(input("enter a number: "))
๐๏ธ Working with Lists
Lists store collections of items under a single variable name using square brackets [ ].
# Empty List
emptylist = []
# List with items
MyList = ["Kuala Lumpur", "London", "Paris", "New York", "Bangkok"]
Indexing: Lists start counting from index 0.
โข Print index 0: print(MyList[0]) -> Prints Kuala Lumpur.
โข Print a range: print(MyList[0:3]) -> Prints indexes 0, 1, 2.
โข Format range print: print(*MyList[0:3], sep=", ") -> Removes brackets and separates with
commas.
โข Right-to-left: print(MyList[-1]) -> Prints the last item Bangkok.
๐ ๏ธ Interactive List Playground
Play with the list visualization below! Modify items or slice ranges to see the changes visually.
๐ข Turtle Graphics Module
The turtle module is a built-in Python library used to introduce programming concepts through drawing shapes, lines, and patterns on a cartesian canvas.
By controlling an on-screen cursor (the "turtle") using commands like forward() and right(), you can create custom graphics, explore geometry, and practice core concepts like loops, variables, and custom procedures.
import turtle
import turtle
turtle.speed(3)
turtle.pensize(8)
turtle.pencolor("black")
turtle.penup()
turtle.goto(-160, 0)
turtle.setheading(45)
turtle.pendown()
for step in range(5):
turtle.forward(45)
turtle.right(90)
turtle.forward(45)
turtle.left(90)
turtle.hideturtle()
print("Zigzag complete")
๐ Turtle Examples to Try
These examples are designed for the main Python editor. Click Edit on any snippet to open it in Turtle mode and adapt the drawing.
Colour Wheel
import turtle
turtle.speed(0)
turtle.bgcolor("midnightblue")
turtle.pensize(2)
colours = ["cyan", "gold", "hotpink", "lime", "orange", "white"]
for i in range(36):
turtle.pencolor(colours[i % len(colours)])
turtle.circle(70)
turtle.right(10)
turtle.hideturtle()
print("Colour wheel complete")
Constellation Map
goto() to place points around the canvas. It practises absolute movement without copying any of the course drawing targets.
import turtle
turtle.speed(0)
turtle.bgcolor("midnightblue")
turtle.pencolor("white")
points = [(-150, 90), (-80, 130), (-20, 70), (55, 120), (120, 50)]
for x, y in points:
turtle.penup()
turtle.goto(x, y)
turtle.dot(8, "gold")
turtle.penup()
turtle.goto(points[0])
turtle.pendown()
for x, y in points[1:]:
turtle.goto(x, y)
turtle.hideturtle()
print("Constellation complete")
Function Flower
import turtle
turtle.speed(0)
turtle.bgcolor("honeydew")
def petal(colour):
turtle.color("darkgreen", colour)
turtle.begin_fill()
for i in range(2):
turtle.circle(60, 60)
turtle.left(120)
turtle.end_fill()
for i in range(12):
petal("lightcoral")
turtle.right(30)
turtle.color("goldenrod", "gold")
turtle.penup()
turtle.goto(0, -25)
turtle.setheading(0)
turtle.pendown()
turtle.begin_fill()
turtle.circle(25)
turtle.end_fill()
turtle.hideturtle()
print("Flower complete")
Labelled Points
goto(), dot() and write() without solving a course drawing task.
import turtle
turtle.speed(0)
turtle.bgcolor("white")
turtle.pencolor("navy")
places = [
("Start", -140, 80),
("Checkpoint", -20, 20),
("Goal", 120, -70)
]
for label, x, y in places:
turtle.penup()
turtle.goto(x, y)
turtle.dot(10, "tomato")
turtle.forward(12)
turtle.write(label, font=("Arial", 12, "bold"))
turtle.hideturtle()
print("Labels complete")
๐ Turtle Movement Commands
Control the turtle's direction and coordinate position on the grid. By default, the turtle starts at coordinates (0,0) pointing to the right (East).
Forward and Turn Trail
forward(), left() and right(). It makes a trail, not a course target shape, so students can focus on how turns affect direction.
import turtle
turtle.speed(4)
turtle.pencolor("royalblue")
turtle.forward(80)
turtle.left(60)
turtle.forward(60)
turtle.right(120)
turtle.forward(60)
turtle.left(60)
turtle.forward(80)
turtle.hideturtle()
print("Trail complete")
Compass Directions
setheading() to point the turtle in exact compass directions. It shows that 0, 90, 180 and 270 are useful headings.
import turtle
turtle.speed(4)
turtle.pencolor("darkgreen")
for heading in [0, 90, 180, 270]:
turtle.setheading(heading)
turtle.forward(80)
turtle.backward(80)
turtle.hideturtle()
print("Compass complete")
Jump Without Drawing
penup(), goto() and pendown() to move the turtle without leaving unwanted joining lines.
import turtle
turtle.speed(4)
turtle.pencolor("purple")
positions = [(-120, 40), (-40, -30), (50, 60), (130, -20)]
for x, y in positions:
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
turtle.forward(35)
turtle.hideturtle()
print("Jump path complete")
turtle.forward(distance)
Moves the turtle forward in its current direction by the specified pixel distance.
Short alias:fd(distance)
turtle.backward(distance)
Moves the turtle backward, opposite to its current heading.
Short aliases:bk(distance), back(distance)
turtle.right(angle)
Turns the turtle clockwise by the specified angle in degrees.
Short alias:rt(angle)
turtle.left(angle)
Turns the turtle counter-clockwise by the specified angle in degrees.
Short alias:lt(angle)
turtle.goto(x, y)
Moves the turtle directly to coordinates (x, y) on the canvas.
setpos(x, y), setposition(x, y)
turtle.setheading(angle)
Sets the turtle direction. 0 is east, 90 is north, 180 is west and 270 is south.
seth(angle)
turtle.home()
Moves the turtle back to (0, 0) and points it east.
turtle.xcor() / turtle.ycor()
Returns the current x-coordinate or y-coordinate.
turtle.pos()
Returns the turtle's current position as a coordinate pair.
Short alias:position()
turtle.heading()
Returns the turtle's current heading angle.
๐ Movement Activity Cards
Task cards for student activities focusing on movement, coordinates, and basic turning:
โ๏ธ Pen & Fill Commands
Control the drawing state of the turtle's pen, customize outlines, and fill shapes with colors.
turtle.penup()
Lifts the pen off the canvas. Moving the turtle will not draw any lines.
Short aliases:pu(), up()
turtle.pendown()
Lowers the pen onto the canvas, so movement draws lines again.
Short aliases:pd(), down()
turtle.pencolor(color)
Sets the outline colour, such as "navy", "red" or "#22c55e".
turtle.fillcolor(color)
Sets the colour used between begin_fill() and end_fill().
turtle.color(pen, fill)
Sets both the outline colour and fill colour. With one argument, it sets both to the same colour.
turtle.pensize(width)
Sets the thickness of the drawing outline in pixels.
Short alias:width(width)
turtle.begin_fill()
Call this right before drawing the closed shape you want to fill.
turtle.end_fill()
Call this after drawing the shape. Turtle fills it with the current fill colour.
Colour Swatch Chart
color(), begin_fill() and end_fill() work together. It draws a swatch chart so students can test supported colour names.
import turtle
colors = ["red", "orange", "yellow", "green", "blue", "purple",
"pink", "brown", "gray", "black", "white"]
square_size = 30
gap = 15
spacing = square_size + gap
turtle.penup()
turtle.speed(0)
start_x = -130
start_y = 120
for index in range(len(colors)):
row = index // 6
col = index % 6
x = start_x + col * spacing
y = start_y - row * 90
# Draw colour swatch
turtle.goto(x, y)
turtle.color(colors[index])
turtle.begin_fill()
for side in range(4):
turtle.forward(square_size)
turtle.right(90)
turtle.end_fill()
# Write colour name
turtle.goto(x, y - 50)
turtle.color("black")
turtle.write(colors[index], align="left", font=("Arial", 10, "normal"))
turtle.hideturtle()
print("Colour swatches complete")
Filled Progress Bar
import turtle
turtle.speed(0)
def rectangle(width, height, outline, fill):
turtle.color(outline, fill)
turtle.begin_fill()
for side in range(2):
turtle.forward(width)
turtle.right(90)
turtle.forward(height)
turtle.right(90)
turtle.end_fill()
turtle.penup()
turtle.goto(-150, 30)
turtle.pendown()
rectangle(300, 45, "black", "lightgray")
turtle.penup()
turtle.goto(-145, 25)
turtle.pendown()
rectangle(210, 35, "seagreen", "mediumseagreen")
turtle.penup()
turtle.goto(-30, -40)
turtle.color("black")
turtle.write("70% complete", align="center", font=("Arial", 14, "bold"))
turtle.hideturtle()
print("Progress bar complete")
๐ Pen & Fill Activity Cards
Task cards for student activities focusing on line thickness, outlines, and color filling:
๐จ Turtle Styling
Change how the turtle and its marks look: cursor shape, drawing speed, dots, circles, labels and visibility.
turtle.circle(radius)
Draws a circle. The centre is one radius to the left of the turtle.
turtle.dot(size, color)
Draws a solid circular dot at the turtle's current position.
turtle.shape(name)
Changes the cursor shape. Try "turtle", "arrow", "circle", "square" or "triangle".
turtle.speed(level)
Sets drawing speed. Use 1 for slow, 10 for fast or 0 for instant drawing.
turtle.write(text, align, font)
Writes text on the canvas. For example, use align="center" to centre the label.
turtle.hideturtle()
Hides the cursor, which makes finished drawings cleaner.
Short alias:ht()
turtle.showturtle()
Makes the turtle cursor visible again.
Short alias:st()
Marker Labels
dot() and write() to place labelled markers. It is useful for showing how styling commands can add readable annotations to a drawing.
import turtle
turtle.speed(0)
turtle.shape("turtle")
turtle.pencolor("navy")
markers = [
("A", -120, 80, "tomato"),
("B", 0, 20, "gold"),
("C", 120, -60, "mediumseagreen")
]
for label, x, y, colour in markers:
turtle.penup()
turtle.goto(x, y)
turtle.dot(18, colour)
turtle.forward(14)
turtle.write(label, font=("Arial", 14, "bold"))
turtle.hideturtle()
print("Markers complete")
Circle Labels
circle(), dot(), write() and hideturtle() to create labelled markers using supported styling commands.
import turtle
turtle.speed(0)
turtle.pencolor("darkslateblue")
items = [("Small", -110, 0, 25), ("Medium", 0, 0, 40), ("Large", 125, 0, 55)]
for label, x, y, radius in items:
turtle.penup()
turtle.goto(x, y - radius)
turtle.pendown()
turtle.circle(radius)
turtle.penup()
turtle.goto(x, y)
turtle.dot(8, "tomato")
turtle.goto(x, y - radius - 24)
turtle.write(label, align="center", font=("Arial", 10, "bold"))
turtle.hideturtle()
print("Circle labels complete")
๐ Styling & Circle Art Activity Cards
Task cards for student activities focusing on complex styling, circle repetition, and combining features:
โฆ Canvas Configuration
The browser Turtle canvas in Python Code Lab uses a fixed visible drawing area of about -200 to 200 on both axes. Use movement and coordinates to position drawings inside that space.
turtle.bgcolor(color)
Sets the background colour of the drawing canvas.
turtle.clear()
Clears the drawing but keeps the turtle's current position and direction.
turtle.reset()
Clears the drawing, resets styles and returns the turtle to (0, 0).
Canvas Coordinate Grid
-200 to 200 coordinate area used by the browser Turtle canvas. It helps students understand where goto(x, y) positions are on screen.
import turtle
turtle.speed(0)
turtle.penup()
# Draw the outer square from -200 to 200
turtle.goto(-200, 200)
turtle.pendown()
turtle.pensize(3)
for side in range(4):
turtle.forward(400)
turtle.right(90)
# Draw grid lines every 50 pixels
turtle.pensize(1)
for x in range(-150, 200, 50):
turtle.penup()
turtle.goto(x, 200)
turtle.pendown()
turtle.goto(x, -200)
for y in range(-150, 200, 50):
turtle.penup()
turtle.goto(-200, y)
turtle.pendown()
turtle.goto(200, y)
# Draw the x-axis and y-axis
turtle.pensize(2)
turtle.penup()
turtle.goto(-200, 0)
turtle.pendown()
turtle.goto(200, 0)
turtle.penup()
turtle.goto(0, 200)
turtle.pendown()
turtle.goto(0, -200)
# Label the corners inside the area
turtle.penup()
turtle.goto(-195, 180)
turtle.write("(-200, 200)", align="left", font=("Arial", 9, "normal"))
turtle.goto(195, 180)
turtle.write("(200, 200)", align="right", font=("Arial", 9, "normal"))
turtle.goto(-195, -195)
turtle.write("(-200, -200)", align="left", font=("Arial", 9, "normal"))
turtle.goto(195, -195)
turtle.write("(200, -200)", align="right", font=("Arial", 9, "normal"))
# Label the centre
turtle.goto(5, 5)
turtle.write("(0, 0)", align="left", font=("Arial", 9, "normal"))
turtle.hideturtle()
print("Canvas grid complete")
Centred Canvas Demo
import turtle
turtle.speed(0)
turtle.bgcolor("lavender")
turtle.penup()
turtle.goto(-95, 45)
turtle.pendown()
turtle.color("navy", "white")
turtle.begin_fill()
for side in range(2):
turtle.forward(190)
turtle.right(90)
turtle.forward(90)
turtle.right(90)
turtle.end_fill()
turtle.penup()
turtle.goto(0, 8)
turtle.color("navy")
turtle.write("Fixed canvas", align="center", font=("Arial", 14, "bold"))
turtle.goto(0, -22)
turtle.write("Keep drawings near the centre", align="center", font=("Arial", 10, "normal"))
# Try uncommenting one of these lines:
# turtle.clear()
# turtle.reset()
turtle.hideturtle()
print("Canvas demo complete")
๐ Shape Builder Example
This compact example is useful for teaching variables and procedures because students can change the number of sides, size and colours.
import turtle
turtle.speed(0)
def polygon(sides, length, outline, fill):
turtle.color(outline, fill)
turtle.begin_fill()
for i in range(sides):
turtle.forward(length)
turtle.right(360 / sides)
turtle.end_fill()
for sides in range(3, 9):
polygon(sides, 70, "navy", "lightgreen")
turtle.penup()
turtle.forward(95)
turtle.pendown()
turtle.hideturtle()
print("Shape builder complete")
โฆ 2D Lists: Rows and Columns
A 2D list is a list containing other lists. Use grid[row][column] to access one cell. Rows and
columns both start at index 0.
seats = [
["A", "A", "B"],
["A", "B", "A"],
["A", "A", "A"]
]
print(seats[0][2]) # B
seats[1][1] = "A" # update row 1, column 1
๐ฏ Pick a Cell, Build the Code
Choose a sample grid, then click a cell. The Python code updates to show the exact
grid[row][column] access and a short example of using that value effectively.
๐ Traversing a Grid
Nested loops visit every cell. The outer loop usually controls the row; the inner loop controls each column in that row.
total = 0
sales = [
[10, 12, 9],
[7, 11, 15]
]
for row in sales:
for value in row:
total = total + value
print(total)
๐พ Reading and Writing Files
File handling lets programs save data after the program stops. Use "r" to read,
"w" to overwrite, and "a" to append to the end.
The standard, recommended practice in Python is to use the with statement (context manager). This ensures that files are automatically and properly closed when the block is exited, even if an error/exception occurs during execution.
1. Writing to a File (Overwrite Mode)
Opening a file with "w" writes new data to it. WARNING: This completely overwrites the file. Any old contents will be lost!
# Overwrites the file completely
with open("score.txt", "w") as file:
file.write("120\n")
2. Appending to a File (Append Mode)
Opening a file with "a" preserves the existing file contents and adds new data at the end.
# Appends data to the end of the file
with open("score.txt", "a") as file:
file.write("150\n")
3. Reading from a File (Read Mode)
Opening a file with "r" allows you to read from it.
# Reads contents from the file
with open("score.txt", "r") as file:
first_score = int(file.readline())
second_score = int(file.readline())
print(first_score) # 120
print(second_score) # 150
๐ Looping Through Lines
Many A-level file tasks load text, split records, count words, or filter rows. strip() removes
the newline at the end of each line. We use the with statement here as well to guarantee proper closing.
with open("players.tsv", "r") as file:
for line in file:
fields = line.strip().split("\t")
name = fields[0]
rating = int(fields[1])
if rating >= 80:
print(name)
๐ Dictionaries: Key-Value Pairs
A dictionary stores values under named keys. It is useful when a list index is not meaningful enough.
moon_counts = {
"Mercury": 0,
"Earth": 1,
"Mars": 2
}
print(moon_counts["Earth"])
print(moon_counts.get("Venus", "Not stored"))
Safe access: .get() avoids a KeyError if the key is missing.
๐ Keys, Values and List Values
Keys must be unique. If you use the same key twice, the later value replaces the earlier one. Values can be strings, numbers, lists, booleans or even another dictionary.
museum = {
"Dinosaurs": ["Triceratops", "Stegosaurus"],
"Planets": ["Mars", "Jupiter"],
"Open rooms": 6
}
print(museum["Dinosaurs"])
print(museum["Dinosaurs"][0])
print(museum["Open rooms"])
๐ก๏ธ Safe Lookup and Membership
Use in when you need to test whether a key exists. Use .get() when you want a safe
fallback value.
shelf_codes = {
"Graphic novels": "A12",
"Robotics": "B07",
"Space": "C04"
}
section = input("Library section: ")
if section in shelf_codes:
print(shelf_codes[section])
else:
print("Not found")
print(shelf_codes.get("Poetry", "Ask the librarian"))
๐ Dictionary Loops and Frequencies
Dictionaries are excellent for counting frequencies because each word can become a key and its count can become the value.
counts = {}
events = ["login", "save", "login", "print", "save", "login"]
for event in events:
counts[event] = counts.get(event, 0) + 1
for event, count in counts.items():
print(event, count)
๐ Looping Through Keys, Values and Items
A normal dictionary loop gives keys. Use .values() for values and .items() when you
need both the key and the value.
bus_times = {
"North Gate": "07:40",
"Sports Hall": "07:55",
"Library": "08:05"
}
for stop in bus_times:
print(stop)
for time in bus_times.values():
print(time)
for stop, time in bus_times.items():
print(stop, "pickup is", time)
.keys().values().items()โ๏ธ Updating, Adding, Deleting and Popping
Assigning to a key updates it if the key already exists, or adds a new pair if the key is new.
del removes a pair. pop() removes a pair and returns its value.
inventory = {
"torch": 3,
"battery": 12,
"map": 1,
"rope": 2
}
inventory["torch"] = 4 # update existing key
inventory["compass"] = 1 # add new key
del inventory["rope"]
removed = inventory.pop("battery")
print("Removed:", removed)
print(inventory)
๐งฑ Nested Dictionaries
A nested dictionary stores a dictionary inside another dictionary. This is useful for records such as bookings, products, characters or teams.
workshops = {
"robotics": {"room": "Lab 2", "places": 18, "level": "intermediate"},
"animation": {"room": "Studio", "places": 12, "level": "beginner"},
"cyber": {"room": "Lab 4", "places": 16, "level": "advanced"}
}
print(workshops["cyber"]["places"])
for workshop, details in workshops.items():
print(workshop, details["room"], details["level"])
Pattern: use the outer key first, then the inner key:
workshops["cyber"]["places"].
๐ Word Frequency From a File
A common dictionary task is counting how often each word appears. Clean the text, split it into words, then update a count for each word.
import string
signal_counts = {}
with open("weather_report.txt", "r") as file:
text = file.read().lower()
for mark in string.punctuation:
text = text.replace(mark, " ")
words = text.split()
for word in words:
signal_counts[word] = signal_counts.get(word, 0) + 1
print("Different words:", len(signal_counts))
print("rain:", signal_counts.get("rain", 0))
๐งฉ Procedures, Functions and Parameters
A procedure performs a named block of steps. A function returns a value. Parameters are variable names in the definition; arguments are the values passed in the call.
def print_receipt(name, price):
print(name, "costs", price)
def add_tax(price):
return price * 1.06
total = add_tax(100)
print_receipt("Keyboard", total)
๐ฏ Scope, Return and Decomposition
Local variables exist inside a function. Global variables exist outside. Good programs decompose a large problem into smaller subroutines with clear jobs.
def is_valid_mark(mark):
if mark < 0 or mark > 100:
return False
return True
mark = int(input("Mark: "))
if is_valid_mark(mark):
print("Accepted")
else:
print("Rejected")
๐ Parameters and Arguments
A parameter is the variable name in the subroutine definition. An argument is the real value sent into the subroutine when it is called.
def announce_train(destination, platform):
print("Train to", destination)
print("Platform", platform)
announce_train("Ipoh", 3)
announce_train("Seremban", 7)
destination and platform"Ipoh", 3, "Seremban" and 7โฉ๏ธ Return Values
A procedure performs actions. A function calculates or chooses a value and sends it back with
return. Store the returned value if you need it later.
def delivery_cost(distance_km):
base = 4
per_km = 1.5
return base + distance_km * per_km
short_trip = delivery_cost(3)
long_trip = delivery_cost(12)
print(short_trip)
print(long_trip)
๐งฎ Using Return Values in Expressions
A function call can be used anywhere its returned value makes sense: in a calculation, comparison, variable assignment, or another function call.
def minutes_to_seconds(minutes):
return minutes * 60
def total_lesson_seconds(lesson_count, minutes_each):
return lesson_count * minutes_to_seconds(minutes_each)
total = total_lesson_seconds(5, 45)
print("Total seconds:", total)
if minutes_to_seconds(10) > 500:
print("Longer than 500 seconds")
๐ช Early Return
A return statement ends the function immediately. This is useful for validation because you can
reject invalid data before the main calculation runs.
def ticket_price(age):
if age < 0:
return "Invalid age"
if age < 12:
return 8
if age >= 65:
return 6
return 12
print(ticket_price(9))
print(ticket_price(40))
print(ticket_price(-3))
๐ฆ Local Scope and Global Scope
Variables created inside a function are local to that function. Return a new value instead of secretly changing a global value.
temperature = 28
def add_heat(current_temperature, increase):
new_temperature = current_temperature + increase
return new_temperature
updated = add_heat(temperature, 4)
print("Original:", temperature)
print("Updated:", updated)
๐งบ Mutable Arguments
Lists and dictionaries are mutable. If a procedure changes a list or dictionary that was passed in, the original collection changes too.
def record_scan(log, item_code):
log.append(item_code)
scanned_items = []
record_scan(scanned_items, "BK-104")
record_scan(scanned_items, "USB-210")
print(scanned_items)
๐งฑ Decomposition Pattern
Decomposition means splitting a program into small named jobs. A good helper should have one clear purpose.
def clean_name(name):
return name.strip().title()
def create_badge(name, group):
tidy_name = clean_name(name)
return tidy_name + " - Group " + group
def print_badge(name, group):
badge = create_badge(name, group)
print("[" + badge + "]")
print_badge(" maya ", "C")
clean_name()prepares data.create_badge()builds a value and returns it.print_badge()handles output.
โ Validation vs Verification
Validation checks whether data is sensible before processing. Verification checks whether data has been copied or entered accurately.
presencerangelengthtypeformat๐งช Try Common Checks
These are the same kinds of checks used in the validation and verification course: range, length, type, presence, format, visual check and double entry.
๐ Input Validation Loop
A validation loop keeps asking until the data passes the required check.
mark_text = input("Enter mark 0-100: ")
while not mark_text.isdigit() or int(mark_text) < 0 or int(mark_text) > 100:
print("Invalid mark")
mark_text = input("Enter mark 0-100: ")
mark = int(mark_text)
print("Accepted:", mark)
๐ Searching Algorithms
Linear search checks items one by one. Binary search needs sorted data and repeatedly discards half of the search space.
items = [3, 8, 12, 20, 31]
target = 20
low = 0
high = len(items) - 1
found = False
while low <= high and not found:
mid = (low + high) // 2
if items[mid] == target:
found = True
elif target < items[mid]:
high = mid - 1
else:
low = mid + 1
print(found)
๐ง Searching Exam Checklist
linear searchbinary searchworst caselog2(n) splits.๐ Sorting and Big O
Sorting algorithms arrange data into order. Complexity describes how work grows as the input size
n grows.
O(1)O(log n)O(n)O(n^2)๐ Big O Growth Visualizer
Move n to see how the common complexity classes grow. The numbers are simplified operation
counts so the shape is clear; this is about comparing growth, not timing real hardware.
๐ Python Examples to Try
These are static code examples in this manual, not an embedded editor. Use the Edit button on a snippet to open it in the Python editor and try it there.
O(1) Constant
One direct lookup.
scores = [82, 91, 77, 88]
first = scores[0]
print(first)
O(log n) Binary Search
The search space halves each step.
items = [3, 8, 12, 20, 31, 44, 50, 72]
target = 44
low = 0
high = len(items) - 1
found = False
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
found = True
break
elif target < items[mid]:
high = mid - 1
else:
low = mid + 1
print(found)
O(n) Linear Search
One pass through the list.
items = [3, 8, 12, 20, 31, 44, 50, 72]
target = 44
found = False
for item in items:
if item == target:
found = True
print(found)
O(n log n) Merge Sort
Split into halves, then merge each level. (Not in A-level)
def merge(left, right):
result = []
while len(left) > 0 and len(right) > 0:
if left[0] < right[0]:
result.append(left.pop(0))
else:
result.append(right.pop(0))
return result + left + right
def merge_sort(items):
if len(items) <= 1:
return items
mid = len(items) // 2
left = merge_sort(items[:mid])
right = merge_sort(items[mid:])
return merge(left, right)
print(merge_sort([7, 3, 9, 2, 6]))
O(nยฒ) Bubble Sort
Nested comparisons over the data. Note that Big O represents the worst-case scenario, so both Bubble Sort and Insertion Sort share this same O(nยฒ) time complexity.
values = [7, 3, 9, 2, 6]
n = len(values)
for pass_num in range(n):
for i in range(n - 1):
if values[i] > values[i + 1]:
values[i], values[i + 1] = values[i + 1], values[i]
print(values)
O(2โฟ) Naive Fibonacci
Each call branches into two more calls.
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(8))
O(n!) Permutations
Try every possible ordering.
from itertools import permutations
items = ["A", "B", "C"]
for ordering in permutations(items):
print(ordering)
๐ซง Interactive Bubble Sort
Bubble sort repeatedly compares neighbouring items and swaps them when they are in the wrong order. Step through the comparisons one at a time.
๐ป Bubble Sort Implementation
Here is a complete Python implementation of the bubble sort algorithm to sort a list of numbers.
def bubble_sort(arr):
n = len(arr)
for i in range(n):
# Last i elements are already in place
for j in range(0, n - i - 1):
# Swap if the element found is greater than the next element
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
numbers = [7, 3, 9, 2, 6]
bubble_sort(numbers)
print("Sorted list:", numbers)
๐ง Bubble Sort Trace
In exams, students often lose marks because they describe sorting in general instead of the exact pass pattern. Use this trace language.
๐ฅ Interactive Insertion Sort
Insertion sort builds a sorted section on the left. Each new key moves left until it reaches its correct position.
๐ป Insertion Sort Implementation
Here is a complete Python implementation of the insertion sort algorithm to sort a list of numbers.
def insertion_sort(arr):
# Traverse from 1 to len(arr)
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
# Move elements of arr[0..i-1], that are greater than key,
# to one position ahead of their current position
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
numbers = [7, 3, 9, 2, 6]
insertion_sort(numbers)
print("Sorted list:", numbers)
๐ง Insertion Sort Trace
Insertion sort grows a sorted section from the left. Each new key is inserted into the correct place inside that section.
keyshiftsorted section๐ Stacks
A stack is a Last In, First Out structure. The newest item is always the next item removed.
pushpoppeek๐๏ธ Stack Visual
Watch how every operation happens at the top of the stack.
๐ป Stack Implementations
Use the list-based version to learn the behaviour quickly. Use the OOP version when the stack should protect its own data and expose named methods.
List-based stack
stack = []
stack.append("scan")
stack.append("pack")
stack.append("label")
top_item = stack[-1]
removed = stack.pop()
print("Top was:", top_item)
print("Removed:", removed)
print(stack)
OOP stack class
class Stack:
def __init__(self, limit):
self.__items = []
self.__limit = limit
def push(self, item):
if len(self.__items) == self.__limit:
return "Overflow"
self.__items.append(item)
return "Pushed"
def pop(self):
if len(self.__items) == 0:
return "Underflow"
return self.__items.pop()
def peek(self):
if len(self.__items) == 0:
return None
return self.__items[-1]
work = Stack(3)
work.push("scan")
work.push("pack")
print(work.peek())
print(work.pop())
๐ง Stack Exam Checklist
- Use
topto track the most recent item. - Check for overflow before pushing onto a fixed-size stack.
- Check for underflow before popping from an empty stack.
- Remember that
pop()removes and returns an item;peek()only reads it.
๐ถ Queues
A queue is a First In, First Out structure. New items join at the rear, and old items leave from the front.
enqueuedequeuefront/rear๐๏ธ Queue Visual
See the difference between the front and rear of the queue.
๐ป Queue Implementations
The list-based version is short and readable. The OOP version makes the queue behaviour explicit through
enqueue(), dequeue() and front().
List-based queue
queue = []
queue.append("ticket-101")
queue.append("ticket-102")
queue.append("ticket-103")
next_item = queue[0]
served = queue.pop(0)
print("Next was:", next_item)
print("Served:", served)
print(queue)
OOP queue class
class Queue:
def __init__(self, limit):
self.__items = []
self.__limit = limit
def enqueue(self, item):
if len(self.__items) == self.__limit:
return "Overflow"
self.__items.append(item)
return "Enqueued"
def dequeue(self):
if len(self.__items) == 0:
return "Underflow"
return self.__items.pop(0)
def front(self):
if len(self.__items) == 0:
return None
return self.__items[0]
service = Queue(3)
service.enqueue("ticket-101")
service.enqueue("ticket-102")
print(service.front())
print(service.dequeue())
๐ง Queue Pointer Checklist
frontpoints to the next item to leave the queue.rearpoints to the newest item added to the queue.- In a circular queue, pointers wrap back to index
0after the final position. - Overflow means enqueueing into a full fixed-size queue; underflow means dequeueing from an empty queue.
๐ Linked Lists
A linked list is made from nodes. Each node stores data and a pointer to the next node. A null pointer marks the end.
List-based linked list using indexes
data = ["badge", "lanyard", "map"]
next_index = [1, 2, -1]
start = 0
current = start
while current != -1:
print(data[current])
current = next_index[current]
OOP linked list using nodes
class Node:
def __init__(self, data):
self.data = data
self.next = None
start = Node("badge")
start.next = Node("lanyard")
start.next.next = Node("map")
current = start
while current is not None:
print(current.data)
current = current.next
Vocabulary: node, pointer, start pointer, null pointer, free list, traversal.
๐๏ธ Linked List Visual
Nodes do not need to sit next to each other in memory. Each node points to the next node.
๐ง Linked List Operations
next pointer until
None.๐ Recursion
Recursion is when a function solves a problem by calling itself. Every recursive algorithm needs a base case to stop and a general case that moves closer to the base case.
def factorial(n):
if n == 0:
return 1 # base case
return n * factorial(n - 1) # general case
print(factorial(5))
๐ฌ Factorial Call Stack Animation
This shows factorial(4) in two phases: first Python creates new function calls until it reaches
the base case, then each call returns a value back to the previous call.
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
print(factorial(4))
Call stack
Return values
๐ Call Stack and Unwinding
Each recursive call creates a stack frame storing parameters, local variables and a return address. When the base case is reached, the calls return in reverse order. This is called unwinding.
๐ง Recursion Trace Pattern
When tracing recursion, write down each call until the base case, then work backwards as the calls return.
factorial(3)
= 3 * factorial(2)
= 3 * 2 * factorial(1)
= 3 * 2 * 1 * factorial(0)
= 3 * 2 * 1 * 1
= 6
๐๏ธ Introduction to Object-Oriented Programming
Object-oriented programming is a way to organise a program around objects. An object keeps related data and the actions that work on that data together. This is useful when a program has many similar things to track, such as accounts, sensors, bookings, players, products or tree nodes.
Without OOP, related variables can become scattered through a program. With OOP, a class describes the pattern once, then each object stores its own values and can use the same methods.
Loose variables
sensor1_reading = 21.4
sensor2_reading = 33.8
sensor3_reading = 24.1
Class and objects
attributes: location, reading
methods: update(), is_hot()
location: "Lab"
reading: 21.4
location: "Roof"
reading: 33.8
location: "Library"
reading: 24.1
๐งฑ Classes, Objects and Instances
A class is a blueprint. An object is one instance made from that blueprint. Each object can store different values in its attributes.
class Sensor:
def __init__(self, location, reading):
self.location = location
self.reading = reading
lab = Sensor("Lab", 21.4)
roof = Sensor("Roof", 33.8)
print(lab.location, lab.reading)
print(roof.location, roof.reading)
โ๏ธ Constructors, Attributes and self
The constructor __init__ runs when a new object is created. self means the current
object, so self.reading belongs to one specific sensor object.
class Sensor:__init__self.locationSensor("Lab", 21.4)๐ ๏ธ Methods: Object Behaviour
A method is a function inside a class. It normally uses self so it can read or change that
object's attributes.
class Sensor:
def __init__(self, location, reading):
self.location = location
self.reading = reading
def update(self, new_reading):
self.reading = new_reading
def is_hot(self):
return self.reading >= 30
roof = Sensor("Roof", 28.5)
roof.update(31.2)
print(roof.is_hot())
๐ Encapsulation, Getters and Setters
Encapsulation keeps data and the methods that control that data together. Getters read a value. Setters update a value, often with validation.
class Locker:
def __init__(self, number):
self.__number = number
self.__open = False
def get_number(self):
return self.__number
def set_open(self, open_now):
if open_now == True or open_now == False:
self.__open = open_now
def is_open(self):
return self.__open
locker = Locker(42)
locker.set_open(True)
print(locker.get_number(), locker.is_open())
๐ฅ Objects in Lists
Programs often create many objects from one class and store them in a list. A loop can then process every object in the collection.
class Sensor:
def __init__(self, location, reading):
self.location = location
self.reading = reading
sensors = [
Sensor("Lab", 21.4),
Sensor("Roof", 33.8),
Sensor("Library", 24.1)
]
for sensor in sensors:
print(sensor.location, sensor.reading)
๐ Loading File Records into Objects
A common OOP pattern is to read each line from a file, create one object from that line, and append the object to a list. The list stores the collection; the class stores the data and behaviour for one item.
class Plant:
def __init__(self, name, sunlight, water_ml):
self.name = name
self.sunlight = sunlight
self.water_ml = int(water_ml)
def needs_large_drink(self):
return self.water_ml >= 300
plants = []
with open("greenhouse.txt", "r") as file:
for line in file:
line = line.strip()
if line != "":
parts = line.split(",")
plant = Plant(parts[0], parts[1], parts[2])
plants.append(plant)
for plant in plants:
if plant.needs_large_drink():
print(plant.name, "needs", plant.water_ml, "ml")
โจ Dunder Methods: Printing Objects Clearly
Dunder methods have double underscores before and after their names. Python calls them automatically for
special behaviour. __str__ is the most useful starting point because it controls what appears
when you print an object.
class Plant:
def __init__(self, name, sunlight, water_ml):
self.name = name
self.sunlight = sunlight
self.water_ml = water_ml
def __str__(self):
return self.name + " needs " + str(self.water_ml) + " ml of water"
def __repr__(self):
return "Plant(" + repr(self.name) + ", " + repr(self.sunlight) + ", " + repr(self.water_ml) + ")"
fern = Plant("Fern", "shade", 180)
print(fern)
print([fern])
__str__print(object).__repr____eq__a == b.__lt__๐งฌ Inheritance
Inheritance lets a subclass reuse attributes and methods from a superclass. Use it when the subclass really is a specialised type of the superclass.
class Vehicle:
def __init__(self, identifier):
self.identifier = identifier
def describe(self):
print("Vehicle:", self.identifier)
class ElectricBus(Vehicle):
def __init__(self, identifier, battery_percent):
super().__init__(identifier)
self.battery_percent = battery_percent
bus = ElectricBus("BUS-18", 76)
bus.describe()
print(bus.battery_percent)
๐ญ Polymorphism
Polymorphism means different classes can use the same method name, but each class can perform a different action.
class EmailAlert:
def send(self):
print("Sending email")
class ScreenAlert:
def send(self):
print("Showing screen message")
alerts = [EmailAlert(), ScreenAlert()]
for alert in alerts:
alert.send()
๐ฏ Abstraction and Aggregation
Abstraction means choosing the important details and ignoring unnecessary detail. Aggregation means one object stores or uses another object.
class Battery:
def __init__(self, percent):
self.percent = percent
class Tablet:
def __init__(self, name, battery):
self.name = name
self.battery = battery
main_battery = Battery(88)
tablet = Tablet("Art tablet", main_battery)
print(tablet.name, tablet.battery.percent)
๐ OOP ADTs: Stacks, Queues and Linked Lists
Abstract data types describe behaviour, not just storage. An OOP implementation hides the internal list or
pointers behind methods such as push(), pop(), enqueue(),
dequeue(), insert() and search().
push(),
pop() and peek().Node class stores data and the next pointer; a list class controls the
start pointer.๐ณ Binary Trees as OOP Structures
Binary trees are a natural bridge between OOP and recursion. A node object stores data plus left and right references. Insert and search methods usually call themselves on the left or right subtree.
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
root = TreeNode(50)
root.left = TreeNode(25)
root.right = TreeNode(75)
print(root.value)
print(root.left.value)
print(root.right.value)
Pattern: smaller values move to the left reference; larger values move to the right reference.
๐ณ Binary Search Trees
A binary tree node can have up to two children. In a binary search tree, smaller values go left and larger values go right.
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
root = Node(50)
root.left = Node(25)
root.right = Node(75)
This is the same object pattern used in the OOP section: each node stores a value and references to child nodes.
๐ Traversal and Tree Search
In-order traversal visits left subtree, current node, then right subtree. In a binary search tree this outputs values in sorted order.
def inorder(node):
if node is not None:
inorder(node.left)
print(node.value)
inorder(node.right)
๐ง Traversal Order
๐ณ Binary Tree Visualiser
Insert and search values to see the exact path through a binary search tree. Smaller values move left; larger or equal values move right.
๐ A Student's Guide to Debugging Python
Debugging means finding and fixing problems in your code. Bugs are normal. Every programmer creates them. The important skill is learning how to find them calmly and carefully.
๐งญ Debugging Flowchart
Use this routine whenever a program crashes, gives the wrong answer, repeats forever, or appears to do nothing.
print() statements if needed.
๐ Read the Error Message
Python error messages are clues. The most useful information is often near the bottom: the error type, the line number, and the name of the variable or command mentioned.
NameError: name 'scroe' is not defined
This suggests that a variable name has been typed incorrectly. Check the line Python mentions and also the line just before it.
if score > 10
print("You win!")
Python may point at the print() line, but the real problem is the missing colon:
if score > 10:
print("You win!")
โ Check the Simple Things First
Typing
- Are all brackets closed?
- Are all speech marks closed?
- Are variable names spelt correctly?
Python syntax
- Is there a colon after
if,for,whileordef? - Is the indentation correct?
- Have you used the correct capital letters?
Logic
- What answer did you expect?
- What answer did you actually get?
- Where does the value first become wrong?
Python is case-sensitive. score, Score and SCORE are three different
variable names.
๐จ๏ธ Use print() as a Clue
Add temporary print() statements to check what values are stored and which parts of the program
are running.
score = 10
bonus = 5
print("Score is", score)
print("Bonus is", bonus)
total = score + bonus
print("Total is", total)
Remove the extra print statements after fixing the bug.
๐งช Test One Small Part
Large programs are easier to debug when you test one small section at a time. Use simple values where you already know the correct answer.
price = 5
quantity = 3
total = price * quantity
print(total) # Should be 15
- For an average calculator, try
10,10,10. The average should be10. - For a multiplication program, try
2and5. The answer should be10. - For an age checker, test the edge cases:
17,18, and19.
๐ง Common Debugging Situations
Wrong answer
This is a logic error. Work out the correct answer yourself, then follow the values through the program.
Loop will not stop
Check whether the loop variable changes, whether the condition can become false, and whether the update is inside the loop.
List error
Remember that list positions begin at 0. The last item in a three-item list is at position
2.
animals = ["tiger", "panda", "otter"]
print(animals[2]) # otter
print(len(animals)) # 3
๐ How to Ask for Help
Do not just say:
It does not work.
Give useful information instead:
I expected the program to print 15, but it prints 8.
There is no error message.
I think the problem is in the total calculation.
- Include the code.
- Include the full error message.
- Explain what you expected.
- Explain what actually happened.
- Say what you already tried.
๐ Debugging Checklist
- What did I expect to happen?
- What actually happened?
- Is there an error message?
- Which line is mentioned? Did I check the line before it?
- Are spelling, brackets, speech marks, colons and indentation correct?
- Are my variables the correct type?
- Does my loop eventually stop?
- Are my list positions valid?
- Can I print the values?
- Have I changed only one thing at a time?
๐ Further Learning & Reference
If you want to dive deeper into Python programming, these highly recommended tutorials and documentations are excellent places to expand your knowledge:
๐ F-String Comic Academy
Learn how to format strings dynamically using variables and expressions in a 10-level beginner comic academy course featuring Byte and Pixel.
๐ W3Schools Python Tutorial
An exceptionally beginner-friendly, structured guide with simple explanations and lots of small interactive code examples.
๐ Official Python Documentation
The definitive source for Python standard libraries, syntax rules, and official explanations. Great for looking up specific modules or features.
๐ Real Python Tutorials
A collection of high-quality, practical articles and step-by-step guides covering core concepts and real-world Python applications.
๐ Python Search Engines
Looking for a specific function, library, or error solution? Use these specialized search portals to search directly within trusted python documentation:
Python Official Search
Search official guides, modules, and built-in function references.
W3Schools Python Search
Search user-friendly tutorials and code examples on W3Schools.
๐ Search Results
Results matching your query will appear here.