TK Study

Software Engineering › How to answer › Python questions

How to answer Python questions

Python questions are marked on whether the code runs and meets every requirement. The online exam has a Python box. Use the five-step routine, write simple code, and read it back as the computer would. From course notes From NESA material

What it looks like in the real exam

From NESA material 2025 HSC 2025 HSC exam, Q19 (3 marks: string input and selection) and 2025 HSC exam, Q26 (5 marks: a random grid). Sample paper: 2025 NESA sample exam, Q18B (validate a username, 3 marks) and 2025 NESA sample exam, Q21B (a timetable, 5 marks). Familiarisation: 2025 NESA familiarisation exam, Q9B (3 marks) and 2025 NESA familiarisation exam, Q13 (6 marks, a scores table). The question usually gives a description, sometimes a sample output, and you type code into the online Python box (fam Q13 is on the familiarisation exam).

Reasoned No past NESA question in our bank uses Flask routes. Flask appears in the course because the syllabus covers web frameworks (Session management); I include it below as course and general material, verified by running it, but weight your study on the six styles above.

Method (the course’s 5 steps)

  1. Read the question carefully. Note exactly what to output and in what format. Course step 1
  2. Analyse the stimulus (a sample run, a table, a grid, a scenario) and list the requirements. Course step 2
  3. Draft in your head (or in a note): the variables, the loop, the selection, any function. Use the names the question uses. Course step 3
  4. Write the code in the online Python tool. Type constants at the top, define functions before calling them, then the main program. Run it. Course step 4 From NESA material NESA 2025: “code must execute”; call functions in the main program after defining them.
  5. Re-read and check against your requirement list: indentation, quotes, colons, output format. Run once more with a normal and an edge input. Course step 5

Syntax you must be able to write from memory

TaskPython
Input and outputname = input('Name? '), print('Hi ' + name), n = int(input())
Selectionif x > 5: / elif x == 5: / else: (colon and indentation)
Loopsfor i in range(5): (0 to 4), for item in items:, while count < 10:
Listsmarks = [3,5,2], marks[0], marks[-1], marks.append(4), len(marks), sum(marks)
Stringss[:3] first three, s[-1] last, s.isupper(), s.isdigit(), s + '123'
Dictionariesd = {'Ava': 80}, d['Ava'], d['Ben'] = 60, for k in d:
Functionsdef area(w, h): … return w * h; call area(2, 3)
Randomimport random, random.randint(1, 25)
Not equal / equal!=, == (a single = assigns)

Worked example 1: strings and selection (2025 HSC Q19)

2025 HSC exam, Q19 · 3 marks

In an organisation, temporary passwords are automatically generated for new user accounts. Each password is created from the first three letters of the username followed by '123'. For example, the username 'NESA' will have the password 'NES123'. When a user logs in for the first time, they are asked for their username and password. They receive a welcome message or an error message, depending on whether the password entered follows the rules of new user accounts. Write a Python program that asks a new user for their username and password, and then checks whether the password rule has been followed. (3 marks)

Official marking criteria

  • 3 marks: Correct code for the problem.
  • 2 marks: Partially correct code that includes a correct selection structure OR password creation.
  • 1 mark: Some understanding of the scenario and Python.

NESA sample answer

uName = input('What is your username?')
password = input('What is your password?')
passwordP1 = uName[:3]
passwordP1= passwordP1 + '123'
if passwordP1 == password:
      print ('Welcome!')
else:
      print ('Incorrect password entered')

Notes

Marker feedback: process string inputs; use a selection structure; code must execute in the environment; use correct indentation; call functions in the main program after defining them.

Open this question page

From NESA material NESA feedback: process the string inputs; use selection; the code must execute; use correct indentation; call functions after defining them. The slice uName[:3] takes the first three characters. If the sample is not exactly what you type, any code that meets every requirement and runs is fine.

Original practice The sample logic, run with the user “Sam” and password “Sam123” prints “Welcome!”, and with “Sam12” prints “Incorrect password entered”:

uName = input('What is your username? ')
password = input('What is your password? ')
expected = uName[:3] + '123'
if password == expected:
    print('Welcome!')
else:
    print('Incorrect password entered')

Worked example 2: lists, loops and a grid (2025 HSC Q26)

2025 HSC exam, Q26 · 5 marks

[Exact question wording is not published as a paper (online exam). Task as shown by the NESA marking guidelines/mapping grid: Python program: generate 15 unique random numbers from 1 to 25 and print a 5 by 5 grid, with an X in each grid position whose number is in the list and a blank otherwise. Task inferred from the MG sample answer; the exact stem is not published as text]

Official marking criteria

  • 5 marks: Correct Python program that creates a list of unique randomly generated numbers; processes the list correctly; uses selection and looping structures; provides correctly formatted output; uses inbuilt Python functions.
  • 4 marks: Substantially correct, most requirements.
  • 3 marks: Some requirements.
  • 2 marks: One requirement.
  • 1 mark: Some understanding of the problem.

NESA sample answer

import random

randList = []
for x in range(15):
   nextInt = random.randint(1,25)
   while nextInt in randList:
      nextInt = random.randint(1,25)
   randList.append(nextInt)

pos = 0
while pos < 25:
  if pos in randList:
      print ("| X", end=" ")
  else:
      print ("| ", end=" ")
  pos = pos + 1
  if (pos % 5 == 0):
      print("| \n")

Notes

FLAG: the NESA sample tests pos (0 to 24) against numbers 1 to 25, so it is off by one (25 is never marked, 0 never appears). Safer: test pos + 1 in randList. Marker feedback: replicate the grid; use the random library; use selection and looping to access the list; include a method of checking the number of values; use meaningful variable names and constants; avoid overly complex structures such as nested IF loops.

Open this question page · some of the NESA wording or answer is an image or is unpublished, as noted

From NESA material NESA feedback: replicate the grid, use the random library, use selection and looping to access the list, check the number of values, use meaningful names and constants, and avoid overly complex nested IF structures.

Reasoned The official sample lists positions 0 to 24 but tests them against 1 to 25 (a possible NESA off-by-one flagged in the bank). Don’t copy it blindly: decide your own index range and check the start and the end.

Original practice My own version (original), run and checked: it always prints 15 X marks in a 5 by 5 grid.

import random

NUMBERS_NEEDED = 15
GRID_SIZE = 5
MAX_NUMBER = GRID_SIZE * GRID_SIZE      # 25

chosen = []
while len(chosen) < NUMBERS_NEEDED:
    n = random.randint(1, MAX_NUMBER)
    if n not in chosen:                 # keep the numbers unique
        chosen.append(n)

for number in range(1, MAX_NUMBER + 1):
    if number in chosen:
        print('| X ', end='')
    else:
        print('|   ', end='')
    if number % GRID_SIZE == 0:         # end of a row
        print('|')

Constants (GRID_SIZE, NUMBERS_NEEDED) are the “meaningful names and constants” the markers asked for; len(chosen) < NUMBERS_NEEDED is the “check the number of values”.

Worked example 3: validation function (2025 sample Q18b)

2025 NESA sample exam, Q18B · 3 marks

(b) Write a function in Python that will check whether a username satisfies the rules (the four username rules in 18a). (3 marks)

Official marking criteria

  • 3 marks: Correct function in Python to check whether a username satisfies the rules.
  • 2 marks: Partially correct function.
  • 1 mark: Some understanding of the problem and Python.

NESA sample answer

def validate_username(username):
     valid = True

     # length check
     if len(username) < 8:
          valid = False
     elif (not username[0].isupper()):
          valid = False
     elif (not username[-2].islower()):
          valid = False
     elif (not username[-1].isdigit()):
          valid = False

     return valid

Notes

Remember to call the function in the main program after defining it, e.g. print(validate_username(input('Username: '))).

Open this question page

Original practice The rule set here is from the NESA sample; the code below follows the same shape and was checked with passing and failing usernames:

def validate_username(username):
    valid = True
    if len(username) < 8:
        valid = False
    elif not username[0].isupper():
        valid = False
    elif not username[-2].islower():
        valid = False
    elif not username[-1].isdigit():
        valid = False
    return valid

# main program: call the function AFTER defining it
name = input('Username: ')
print(validate_username(name))

Define the function first, call it in the main program after. Return True or False instead of printing inside, unless the question says to print.

Worked example 4: a 6-mark scores program (2025 familiarisation Q13)

2025 NESA familiarisation exam, Q13 · 6 marks

[Question stem not available as text (it is on the interactive NESA familiarisation site). Task per the NESA mapping grid: Python program to display a player's scores and points per round from a list of 10 scores, with bonus points when a round scores 5 (add the next round's score) and a final-round rule (10 points), then the total]

Official marking criteria

  • 6 marks: Substantially correct solution with ALL of: looping correctly; referring to the contents of the data structure correctly; displaying the player's scores and corresponding points as shown; calculating the total points; taking bonus points into account; handling the final round correctly.
  • 5 marks: Most features. 3-4: Some features.
  • 2 marks: One feature.
  • 1 mark: Some understanding.

NESA sample answer

# Input code
scores = [3,5,5,2,1,4,0,1,4,5]

# Display the scores and points

# Header row
print("Round\tScore\tPoints")
totalPoints = 0

# Calculate the points and print
for i in range(len(scores)):
    roundNumber = i + 1
    score = scores[i]
    points = score

    # Check if any bonuses apply and NOT the final round
    if points == 5 and i != 9:
        # Add the points from the next round as bonus points
        points += scores[i + 1]

    # Check if the final round bonus applies
    if points == 5 and i == 9:
        # Give the bonus points of 10
        points = 10

    # Add to the total points tally
    totalPoints += points

    # Print the results
    print(str(roundNumber) + "\t" + str(score) + "\t" + str(points))

print("\nTOTAL POINTS: " + str(totalPoints))

Notes

The full stem is not available; the requirements are inferred from the MG criteria and sample answer. FLAG: in the MG text the comment and the print("Round...") are run together on one line (a typesetting error); they are shown here on separate lines.

Open this question page · some of the NESA wording or answer is an image or is unpublished, as noted

Reasoned The full stem is not published as text (a comment/print-line issue is flagged in the bank), so rely on the sample answer’s structure: a table printed with a for loop, a points rule inside the loop, a special final-round rule, a running total.

Original practice A working program with the same pattern, run to confirm the total of 42:

scores = [3, 5, 5, 2, 1, 4, 0, 1, 4, 5]

print("Round\tScore\tPoints")
totalPoints = 0

for i in range(len(scores)):
    roundNumber = i + 1
    score = scores[i]
    points = score

    # bonus: a 5 in any round except the last adds the NEXT round's score
    if points == 5 and i != 9:
        points += scores[i + 1]

    # final round rule: a 5 in the last round is worth 10
    if points == 5 and i == 9:
        points = 10

    totalPoints += points
    print(str(roundNumber) + "\t" + str(score) + "\t" + str(points))

print("\nTOTAL POINTS: " + str(totalPoints))

Debugging and reading code

From course notes Reading code: trace it like the pseudocode (variables on paper). Debugging: look for the usual four: = instead of +=, off-by-one in range, wrong indentation, return versus print.

Original practice Example: this function should return the average of the marks. It has two bugs (run: buggy gives 24.33…, fixed gives 60.0).

# BUGGY version (what the question gives you)
def average(marks):
    total = 0
    for m in marks:
        total = m                 # BUG 1: replaces the total instead of adding
    return total / len(marks) + 1  # BUG 2: stray + 1

# FIXED version (what you write)
def average_fixed(marks):
    total = 0
    for m in marks:
        total = total + m
    return total / len(marks)

print(average([50, 60, 70]))
print(average_fixed([50, 60, 70]))

Python with a database (sqlite3) and parameterised queries

From course notes Use ? placeholders and pass the values separately. Never join user text into the SQL string: that is how SQL injection works. See Python sqlite3 parameterised query and SQL injection.

import sqlite3

conn = sqlite3.connect(":memory:")          # an exam program would use a file such as "school.db"
cur = conn.cursor()
cur.execute("""CREATE TABLE Student (
                   StudentID INTEGER PRIMARY KEY,
                   Name TEXT NOT NULL,
                   Mark INTEGER)""")

# CREATE / INSERT: always use ? placeholders, never join user text into the SQL
cur.execute("INSERT INTO Student (Name, Mark) VALUES (?, ?)", ("Sam", 85))
cur.execute("INSERT INTO Student (Name, Mark) VALUES (?, ?)", ("Mia", 72))
conn.commit()

# READ
cur.execute("SELECT Name, Mark FROM Student WHERE Mark >= ?", (80,))
for name, mark in cur.fetchall():
    print(name, mark)

# UPDATE and DELETE
cur.execute("UPDATE Student SET Mark = ? WHERE StudentID = ?", (90, 1))
cur.execute("DELETE FROM Student WHERE StudentID = ?", (2,))
conn.commit()

cur.execute("SELECT COUNT(*) FROM Student")
print("rows left:", cur.fetchone()[0])
conn.close()

Original practice Output: Sam 85 then rows left: 1. I also ran an injection test: a joined-string query with ' OR '1'='1 returned every row, the ? version returned none.

Classes, inheritance and overriding

From course notes A class has attributes and methods. A subclass inherits and may override a method. See Inheritance, Method overriding, Python classes and objects.

class Pet:
    def __init__(self, name):
        self.name = name                    # attribute set by the constructor

    def speak(self):
        return self.name + " makes a sound"

class Dog(Pet):                              # inheritance: Dog IS-A Pet
    def speak(self):                         # method overriding (polymorphism)
        return self.name + " barks"

for pet in [Pet("Tom"), Dog("Rex")]:
    print(pet.speak())

Output: Tom makes a sound and Rex barks.

A Flask login with sessions (course and general)

From course notes Routes map a URL to a function; request.form reads a submitted form; session remembers the user between requests; redirect sends the browser elsewhere. I ran this app with Flask’s test client: a wrong password and an injection attempt are rejected, a right login reaches /dashboard, and after /logout the dashboard redirects to the login.

from flask import Flask, render_template, request, redirect, url_for, session
import sqlite3

app = Flask(__name__)
app.secret_key = "change-me"            # signs the session cookie

def check_user(username, password):
    conn = sqlite3.connect("school.db")
    cur = conn.cursor()
    cur.execute("SELECT 1 FROM Users WHERE Username = ? AND Password = ?",
                (username, password))      # parameterised: safe from SQL injection
    found = cur.fetchone() is not None
    conn.close()
    return found

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        if check_user(username, password):
            session["user"] = username     # remember who is logged in
            return redirect(url_for("dashboard"))
        return render_template("login.html", error="Invalid login")
    return render_template("login.html", error=None)

@app.route("/dashboard")
def dashboard():
    if "user" not in session:              # protect the page
        return redirect(url_for("login"))
    return render_template("dashboard.html", user=session["user"])

@app.route("/logout")
def logout():
    session.clear()                        # end the session
    return redirect(url_for("login"))

Common mistakes

  • From NESA material “Code must execute.” A typo (Print, a missing colon) that stops it running loses marks even if the idea is right.
  • From NESA material Functions defined but never called in the main program.
  • From NESA material 2025 Q26: overly complex nested IFs, no constants, wrong keywords or syntax, mishandling list values.
  • General advice input() returns text. int(input()) before you compare numbers.
  • General advice Mixing tabs and spaces. Use 4 spaces for every level.
  • General advice Printing the wrong format. Copy the sample output’s spacing, capitals and punctuation exactly.

Time per mark

Derived 5 marks ≈ 9 minutes, 3 marks ≈ 5 minutes, 6 marks ≈ 10.5 minutes at the paper average of 1.75 minutes per mark. General advice Spend 1 to 2 minutes planning, write the simplest working version first, then add the extra requirements.

Practice (5 items, with answers)

Item 1 · original: even numbers

Write Python that prints the even numbers from 2 to 20, each on its own line.

Show the answer
for n in range(2, 21, 2):
    print(n)

Or for n in range(1, 21): if n % 2 == 0: print(n). Original practice

Item 2 · original: average of a list

Write a function average(marks) that returns the average of a list, then call it with [50, 60, 70] and print the result.

Show the answer
def average(marks):
    return sum(marks) / len(marks)

print(average([50, 60, 70]))

Prints 60.0 (checked). Original practice

Item 3 · original: find the bugs

This should print the highest mark. Fix it.

marks = [40, 85, 60]
highest = 0
for m in marks
    if m > highest
        highest == m
print(highest)
Show the answer
marks = [40, 85, 60]
highest = 0
for m in marks:
    if m > highest:
        highest = m
print(highest)

Bugs: missing colons after for and if; == compares, = assigns. Prints 85. Original practice

Item 4 · original: a class

Write a class Student with a name and a mark, and a method passed() that returns True if the mark is 50 or more.

Show the answer
class Student:
    def __init__(self, name, mark):
        self.name = name
        self.mark = mark

    def passed(self):
        return self.mark >= 50

s = Student("Ava", 80)
print(s.passed())

Prints True. Original practice

Item 5 · original: safe database query

Write the line that finds the student called name using sqlite3, safely.

Show the answer
cur.execute("SELECT * FROM Student WHERE Name = ?", (name,))

Note the one-item tuple needs the trailing comma. Original practice

← How to answer pseudocode questionsHow to answer SQL questions →