English:Modular programming with functions and data structures - Computing Year 9
Introduction
Build an original modular record-reporting program with separate input,analysis and presentation functions. Handle empty data deliberately,complete the required highest-value task and compare a bounded JavaScript equivalent. Year9 is an editorial allocation within England’s KS3 Computing programme.
Design clear function responsibilities and contracts
Divide responsibilities, not just lines
A modular program gives different responsibilities clear interfaces. Input code converts an accepted external representation into structured data. Processing code calculates from that structure. Reporting code turns the result into an appropriate presentation. The parts can be tested separately and combined without an unrelated global variable secretly changing an answer. Creating many tiny functions is not automatically better; each should have a useful responsibility and a documented contract.
Our original project reports invented readings from two fictional zones. Each record contains an ID, zone and whole-number reading. A list holds multiple records; each dictionary names the fields of one record. This abstraction represents only what is needed for selection and summary. It contains no pupil identities, real measurements, dates, units or calibration evidence. A numerical report from these invented values is not a scientific finding or verified performance record.
| Stage | Accepted input | Returned output | Responsibility |
|---|---|---|---|
| parse_records | Restricted classroom text | Validated list of record dictionaries | Convert and reject malformed data |
| analyse_records | Validated records and exact zone choice | Fresh summary dictionary | Select and calculate |
| format_report | The analyser’s summary dictionary | Plain report string | Present an already calculated result |
| build_report | Text and a zone choice | Plain report string | Compose the three stages |
The reporting helper's documented input is the summary produced by the analyser, not an arbitrary untrusted dictionary. The public input and record-analysis boundaries validate their own contracts. The result is returned as data or text; a caller decides whether to print it. Printing a value inside a function without returning it would not supply that value to the next stage.

The chart and a function-call design are different representations. A flowchart shows control/data steps for its stated conversion; it does not prove that a program has separate reusable functions. For the record project, write which data crosses each function boundary and what can fail there. That description is more useful than giving every function a fashionable name.
Corey Schafer: Python functions. Distinguish arguments, local variables and returned values; then explain why the report pipeline should pass its data explicitly. Original: Corey Schafer, Python Tutorial for Beginners 8: Functions. The written explanations and native tasks work without sound or the external player. For the required highest-value task, document that highest accepts an allowed integer list and returns its greatest value, or None when the list is empty. For[7,3,9,2]the result is9. For an empty list there is no greatest stored value. Returning0 instead would confuse absence with a genuine zero and would fail for negative-only data.
Process structured records through an original pipeline
Define the record format before parsing
The original classroom format contains one record per nonblank line:ID, zone, integer. It has no header, quoted fields or embedded commas. It is deliberately not a complete CSV parser. Surrounding field whitespace is trimmed and blank lines are ignored. IDs are R followed by two decimal digits, R00 through R99, and must be unique within a collection. Zones are exactly North or South. A value spelling permits an optional plus/minus and one to three decimal digits;after conversion the accepted value is−100 through 100.
| ID | Zone | Reading |
|---|---|---|
| R01 | North | 4 |
| R02 | South | 6 |
| R03 | North | 8 |
The full collection has count 3, total 18, mean 6 and highest 8. Selecting North preserves R01, R03 in source order and gives count 2, total 12, mean 6, highest 8. Selecting South gives count 1, total 6, mean 6, highest 6. A filter is not deletion:the original record list is preserved. If a valid selected zone has no records, the count and total are zero while mean and highest are None.
The program caps text at 4000 characters and a collection at 20 records. It rejects unknown fields, duplicate IDs, invalid zones, fractional spellings and Boolean values passed as numeric readings. These are teaching boundaries, not a universal file standard. For production interchange, choose and validate an appropriate established format rather than extending a comma split until it silently misreads quoted data.
Complete original Python pipeline
Use a school-approved Python 3 practice environment. Save the complete module as a new practice file and run it there. It uses Python’s standard regular-expression module and needs no network, installation package, account or actual school records. Its main block prints the original examples;importing the module for tests defines functions without running those demonstration prints.
import re
def check_values(values):
if type(values) is not list or len(values) > 20:
raise ValueError("use a list of at most 20 values")
if any(type(v) is not int or not (v >= -100 and 100 >= v) for v in values):
raise ValueError("values must be whole integers from -100 to 100")
def highest(values):
"""Return the greatest accepted integer, or None for no values."""
check_values(values)
best = None
for value in values:
if best is None or value > best:
best = value
return best
def average(values):
"""Return an arithmetic mean, or None when the list is empty."""
check_values(values)
return sum(values) / len(values) if values else None
def check_records(records):
if type(records) is not list or len(records) > 20:
raise ValueError("use at most 20 records")
seen = set()
for record in records:
if type(record) is not dict or set(record) != {"id", "zone", "reading"}:
raise ValueError("each record needs exactly id, zone and reading")
if type(record["id"]) is not str or not re.fullmatch(r"R[0-9]{2}", record["id"]):
raise ValueError("ID must be R00 to R99")
if record["id"] in seen:
raise ValueError("record IDs must be unique")
seen.add(record["id"])
if record["zone"] not in ["North", "South"]:
raise ValueError("zone must be North or South")
check_values([record["reading"]])
def parse_records(text):
"""Read the restricted classroom format ID,zone,integer; not general CSV."""
if type(text) is not str or len(text) > 4000:
raise ValueError("text must be a string of at most 4000 characters")
records = []
for line in text.splitlines():
if not line.strip():
continue
fields = [field.strip() for field in line.split(",")]
if len(fields) != 3 or not re.fullmatch(r"[+-]?[0-9]{1,3}", fields[2]):
raise ValueError("use three fields and a signed decimal integer")
records.append({"id": fields[0], "zone": fields[1], "reading": int(fields[2])})
check_records(records)
return records
def analyse_records(records, zone="All"):
"""Validate records, select an exact zone, and return fresh summary data."""
check_records(records)
if zone not in ["All", "North", "South"]:
raise ValueError("choose All, North or South")
selected = [r for r in records if zone == "All" or r["zone"] == zone]
values = [r["reading"] for r in selected]
return {"zone": zone, "ids": [r["id"] for r in selected],
"count": len(values), "total": sum(values),
"mean": average(values), "highest": highest(values)}
def format_report(summary):
"""Format the dictionary returned by analyse_records; no printing here."""
mean_text = "not available" if summary["mean"] is None else f'{summary["mean"]:.2f}'
high_text = "not available" if summary["highest"] is None else str(summary["highest"])
return (f'Zone: {summary["zone"]}; count: {summary["count"]}; '
f'total: {summary["total"]}; mean: {mean_text}; highest: {high_text}')
def build_report(text, zone="All"):
return format_report(analyse_records(parse_records(text), zone))
if __name__ == "__main__":
sample = "R01,North,4\nR02,South,6\nR03,North,8"
print(build_report(sample))
print(build_report(sample, "North"))
print(build_report(""))
print(highest([7, 3, 9, 2]))
print(highest([]))highest begins with None as an explicit no-value state. The first accepted item replaces that state;later items replace the best only when greater. For[-7,-3]the correct maximum is−3. Initialising best to 0 would incorrectly keep a value that was never present. For an empty list, the loop runs zero times and leaves None. The function does not access element0 before checking the empty case.
average divides by the actual count only when values exist. The source example[4,6,8]has sum18, count 3 and mean 6. A sum of zero does not imply an empty collection:the list[-2,2]has two values and a defined mean 0. The chosen None rule represents missing results without inventing a measurement.
The report formats a defined mean to two decimal places for display. That can round a non-terminating decimal;it must not replace the unrounded calculation in later processing. A displayed1.67 for the mean of[1,2,2]is an approximation to 5/3, not a new exact reading. Keep structured summary data available when the next step needs numbers.

Repeated validation in these small public functions favours explicit safety and easy testing over avoiding every scan. The bound of 20 records makes the teaching trade-off clear. Refactoring a real larger service would need a documented validation boundary and tests;do not drop checks or alter output types merely to claim a faster program.
Test interfaces,compare languages and refactor safely
Test each interface and the composition
Begin with exact normal, empty, boundary and invalid cases. For a processing function, prepare structured input directly so a parser error does not hide an arithmetic issue. For the parser, test conversion and validation separately from presentation. Finally test build_report end to end with the same declared records. Unit-level success is useful but does not prove that the functions are connected correctly.
| Case | Expected result | What it challenges |
|---|---|---|
| highest([7,3,9,2]) | 9 | The required normal case |
| highest([]) | None | An explicit no-data rule |
| highest([-7,-3]) | -3 | A maximum incorrectly initialised to 0 |
| average([-2,2]) | 0.0 | Confusing zero sum with empty data |
| Empty text through build_report | Count0, total 0, mean/highest not available | The complete empty-data path |
| Repeated ID on two lines | ValueError | Ambiguous identity before reporting |
| Reading spelled2.5 | ValueError | An unsupported fractional input |
Compare results with an independent reference and retain exact inputs. Check input preservation as well as values. If a report shows an error, locate the earliest boundary where actual data differs from the contract:raw fields, typed records, selected values, summary or formatted string. Changing a printed label cannot repair a wrong mean. Replacing every function at once makes it harder to identify the cause.
A second textual language, with a deliberately bounded comparison
This complete JavaScript example implements only the required highest-value operation. Run it in a school-approved JavaScript preview or a local JavaScript runtime, not in a signed-in service’s console. JavaScript uses null for the selected no-value result, where the Python version uses None. Both examples reject unsupported values and keep absence distinct from zero. This is a comparison of one interface, not a claim that the entire record application has been ported.
function highestReading(values) {
if (!Array.isArray(values) || values.length > 20 ||
Array.from(values).some(v => !Number.isInteger(v) || !(v >= -100 && 100 >= v))) {
throw new Error("Use at most 20 whole integers from -100 to 100.");
}
let best = null;
for (const value of values) {
if (best === null || value > best) best = value;
}
return best;
}
console.log(highestReading([7, 3, 9, 2]));
console.log(highestReading([]));
console.log(highestReading([-7, -3]));It prints9, null,−3 for its three examples. The variable best belongs to the function call;one call should not retain a previous collection's result. The validation rejects Boolean values, fractions and out-of-range readings. For this exercise, use ordinary dense arrays of explicit entries;language-specific array edge cases need their own contract and tests before broader reuse.
Refactor without changing the agreed behaviour
Suppose a first script reads a text block, converts values, calculates a mean and prints everything in one long sequence. Before dividing it, write normal and empty-case expectations. Extract parsing, analysis and formatting responsibilities, pass the records and summary explicitly, and compare the same test evidence afterwards. If the original empty case was a defect, fix it deliberately and document the new rule rather than claiming perfectly unchanged behaviour.
Filtering is a useful transfer because it connects data structure and modular design. A record keeps a reading associated with an ID and zone;separate uncoordinated lists can accidentally misalign those fields. A summary returns selected IDs so a reviewer can reconcile which rows contributed. Consistent keys and unique IDs reduce ambiguity, while still not proving that invented or imported readings are truthful measurements.
Submit a program with at least three meaningful functions, a documented list/record structure, clear parameters and returns, and evidence for normal, empty, boundary and invalid inputs. Include the required highest 9/emptyNone task, one negative-only check, one filter and a comparison between unrounded analysis and displayed text. State limits honestly:no live data collection, network, persistent storage, certified measurement or automatic learning-points write is part of this practice program.
Interactive Tasks
Quiz: Test Your Knowledge
What makes a useful function interface? (A documented responsibility with explicit inputs,outputs and failure rules) (!An unrelated global variable that silently changes the result) (!Printing every intermediate value instead of returning data) (!Giving every line its own function regardless of purpose)
What does the required highest-value function return for[7,3,9,2]? (9) (!7) (!3) (!2)
What is the chosen Python result for an empty highest-value list? (None) (!0 as a fabricated greatest reading) (!The first list item) (!A previous call’s maximum)
Why does highest begin with None rather than0? (A negative-only list must return a value actually present) (!Zero is greater than every possible accepted reading) (!Every list always contains zero) (!None automatically proves the data is authentic)
What are the original collection’s count,total and mean? (3,18,6) (!2,12,8) (!3,6,18) (!1,6,8)
Which IDs contribute to the North summary? (R01 and R03) (!R02 only) (!All IDs regardless of zone) (!The IDs are discarded before filtering)
What is true about the classroom parser? (It accepts a restricted three-field format and is not a general CSV parser) (!It supports every quoted or embedded-comma CSV field) (!It treats every header as a reading automatically) (!It silently accepts duplicate IDs)
What does format_report return? (A plain string representing an analyser-produced summary) (!A permanent online calendar entry) (!Verified learner points) (!New observations from a real sensor)
What is a good reason to keep the unrounded mean? (Later calculations should not use presentation rounding as exact data) (!Two-decimal text is always a new exact observation) (!Rounding removes every input-validation requirement) (!A string is always better for numeric analysis)
What is the scope of the JavaScript example? (A tested highest-value interface with null as the no-data result) (!A complete port of every Python record function) (!A production school-data service) (!A replacement for every native portal activity)
Memory Game
| Parameter | A named input to a function |
| Return | Provide a result to a caller |
| Record | Related named fields describing one item |
| Parser | Convert an accepted external representation into structure |
| Contract | A stated interface and its conditions |
| Refactoring | Reorganising code while preserving agreed behaviour |
Drag and Drop
| Negative readings incorrectly give a maximum of0 | Replace the fabricated starting maximum with an explicit no-value state |
| An empty list causes division by zero | Define the no-data result before calculating a mean |
| Two rows reuse the same supposedly unique ID | Reject the ambiguous records at the validation boundary |
| A parser is blamed for a wrong numeric total | Test typed analysis separately to locate the first error |
| A rounded display is reused as an exact reading | Keep unrounded structured data separate from presentation |
Crossword Puzzle
| FUNCTION | What groups a useful reusable responsibility? |
| PARAMETER | What names an input accepted by a function? |
| RETURN | What supplies a result back to the caller? |
| RECORD | What keeps related named fields together? |
| PARSER | What converts the restricted input text? |
| INTERFACE | What boundary describes how a part is used? |
LearningApps
Optional extra practice. Choose an appropriate activity with your teacher. If the external collection is unavailable, use the native activities and independent tasks in this course.
Cloze Text
Open Tasks
Easy
- Complete the required maximum task: Find highest for[7,3,9,2]and an empty list,and explain the two results.
- Handle negative readings: Trace best through[-7,-3]and explain why starting at0 fails.
- Read a record: Identify the roles of ID,zone and reading in the original data.
- Separate display from data: Explain return versus print and why a rounded mean remains a display approximation.
Standard
- Build the required modular program: Use at least three meaningful functions with documented parameters,returns and a list or table structure.
- Run the original pipeline: Record All,North,South and empty-text results using the complete module.
- Check invalid records: Design tests for duplicate IDs,unknown zones,extra fields,fractional text and unsupported numeric types.
- Compare two textual languages: Run both highest-value examples and compare9,None/null,zero and negative-only cases.
Advanced
- Refactor with a contract: Extract input,analysis and reporting responsibilities from a monolithic design and show before/after test expectations.
- Evaluate a data structure: Explain how records prevent field misalignment and why a set can lose repeated observations.
- Locate the earliest defect: Describe how isolated parser,analysis and formatting tests narrow down a wrong report.
- Plan responsible extension: Propose an established interchange format or larger data set with explicit validation,performance and privacy requirements.
Learning Check
- Required highest results: State and explain the normal and empty results.
- Original record summary: Give All,North and South numeric summaries.
- Zero versus absence: Compare[-2,2]with an empty value list.
- Interface trace: Explain how build_report composes the three main stages.
- Parser limits: Explain the response to quoted-comma data,duplicate IDs and2.5.
- Tested language comparison: Describe the JavaScript comparison and one remaining limit.
Worked checks and assessment guidance
- highest([7,3,9,2])returns9. highest([])returnsNone because there is no stored greatest value. Initialising best toNone handles both empty and negative-only lists without indexing element0 first.
- All:count3,total18,mean6,highest8. North:R01,R03,count2,total12,mean6,highest8. South:R02,count1,total6,mean6,highest6. Original records and their order are preserved.
- [-2,2]has count2,total0,defined mean0 and highest2. Empty values have count0,total0,meanNone and highestNone. Zero total alone does not indicate missing data.
- parse_records validates/converts restricted text to records;analyse_records validates/selects and returns fresh numeric summary data;format_report accepts that summary and returns a string. The caller prints it if wanted. No unrelated global readings are used.
- The restricted classroom format does not support general quoted CSV;unsupported fields are rejected rather than guessed. Duplicate IDs violate the record contract.2.5is not an accepted whole-integer spelling. A production format needs an appropriate established parser and explicit validation.
- It implements highest-value only,returning9,null and−3 for the declared normal,empty and negative examples. Python usesNone. Both keep absence distinct from zero. This does not establish that the complete record pipeline,all possible array shapes or a networked service have been implemented.
Learning evidence
Submit a modular program,interface notes,record schema,normal/empty/boundary/invalid test evidence,required maximum results,one filter and an explanation of formatting versus unrounded data. Preserve original data during analysis and distinguish invented readings from real measurements. Document the narrow parser and JavaScript comparison scope.
OER and Wikipedia
Python tutorial: function definitions, Python tutorial: data structures and dictionaries, Python tutorial: modules;language semantics,not copied example code. DfE: England KS3 Computing programme;editorial Year9 placement. Primary documents reviewed14November2026. All record data,complete programs,worked results and activities here are original.
Flowgorithm Input Process Output.svg, Dave Braunschweig, CC BY-SA 4.0. Unchanged original; caption and learning activities are original.
Python Code.jpg, Weal2019, CC0. Unchanged original; caption and learning activities are original.
Corey Schafer: Python Tutorial for Beginners 4: Lists, Tuples, and Sets;original publisher support video,not a partnership or relicensing claim.
Linked learning areas
aiMOOC Projects
Schulfach+


aiMOOCs


aiMOOC Projekte


MOOCwiki · Deutsch
Nach dem Lernen ist vor dem Lernen
Entdecke direkt den nächsten Lernkurs. Weitere Inhalte erscheinen, wenn Du weiter nach unten scrollst.
Zur MOOCwiki-HauptseiteMediathek
Mediathek wird aus dem Wiki geladen ...
Keine passenden Inhalte gefunden. Bitte ändere Suche oder Filter.
NEWSLernweltNOAH fragen