DoAssignment study guide

A2.1 · Organize a modular program across files

Learn to organize a modular program across files through clear examples and targeted practice.

Ontario Grade 12 Computer Science

Programming Concepts and Skills

ICS4U A2.1 | Turning one program into cooperating modules

In ICS3U, you learned to write programs using variables, functions, selection, repetition, and input and output. A longer program can become hard to follow if every task is placed in one file. ICS4U expectation A2.1 focuses on organizing a modular program across files: placing related program parts in separate files and arranging for those parts to work together. This lesson uses small Python 3 examples to show the choices involved. The code is for reading and tracing; it has not been run.

What you will learn

  • Explain how dividing a program across files can give related code a clear home.
  • Identify which module should contain a task and which module should coordinate the program.
  • Use Python 3 imports to connect modules and trace how a value moves between them.
  • Check that a multi-file program has the files, names, and inputs its imports require.

1. From one file to cooperating files

A module is a file that holds program code. A modular program uses more than one module, with each file given a clear responsibility. For example, one file might hold functions for calculating a total, while another handles the sequence of steps for a user-facing program. The goal is not to create as many files as possible. The goal is to make it easier to find and understand related code.
A useful starting question is: “What part of the program belongs together?” Put functions that serve the same task in one module. Keep the part that brings the tasks together in a main program file. A function can be defined in one file and used by another after that other file imports the module.
An import connects a file to a module by its module name. In a basic Python 3 project, the files can be placed in the same folder, and the import uses the filename without the .py ending. If the file is named totals.py, the module name is totals. The calling file can then refer to a function as totals.function_name(...). This makes it clear which module supplies the function.
  • A module is a file containing program code.
  • Group related functions in a module and give each file a clear responsibility.
  • Import the module before using names provided by that module.

2. Plan the connection before writing

Before dividing an existing program, list its main tasks and the functions that support them. Decide which functions belong together, choose descriptive filenames, and decide which file will coordinate the overall sequence. Then check how the files will connect: the calling file must import the module, and the name used after the import must match a function defined in that module.
The examples here use a simple arrangement: all project files are in one folder; filenames are valid Python module names; and the functions are defined in the modules that are imported. The input to a function must have the kind of value that its body expects. These are preconditions: facts that must be true for the example to make sense. A multi-file plan should also identify the expected result, so the reader can trace whether the connections are correct.
When tracing, begin with the main file. Follow its statements in order. At an import, note which module becomes available. At a function call, follow the call to the function's definition, use the supplied input, and return to the calling statement with the function's result. This is a reading method, not a claim that the code has been executed.
  • Check filenames, import names, and function names as a connected set.
  • Trace from the coordinating file to the imported function and back.
  • State what inputs a function expects and what result the caller should receive.

3. Keep each file's responsibility visible

A file arrangement should help a reader answer two questions: “Where is this task defined?” and “Where does the program bring its tasks together?” Use names that hint at responsibility, such as totals.py for total-related functions and main.py for the program's coordinating steps. Names such as part1.py give less information about what to look for.
A module import does not automatically make a program well organized. If the main file contains all the calculations while an imported file is unused, the files are separate but are not cooperating in a meaningful way. Similarly, splitting one small task into many hard-to-follow pieces can make the program more difficult to trace. Judge the division by whether related code is easy to locate and the connections are clear.
For a class assignment, state the purpose of each file in a short note or comment if the purpose is not obvious. Keep the program's sequence readable in the coordinating file. Keep a supporting function's calculation with that function rather than copying the same calculation into multiple places. This makes it easier to see where a change belongs.
  • Choose filenames that communicate the file's task.
  • The coordinating file should show how the program's parts are used.
  • A supporting module should actually be used and should hold code related to its responsibility.

4. Check the whole arrangement

Review a multi-file program from both directions. Starting at the coordinating file, verify that each imported module is available and each called function is defined. Starting at each supporting file, verify that its contents fit the role assigned to that file. This catches common organization errors before a reader tries to follow the program.
A useful check is to make a small file map: write each filename, its responsibility, and the names another file uses from it. Then trace one ordinary input through the files. If the trace reaches a missing name, an unused module, or an unclear responsibility, revise the arrangement. The map describes the organization; it is not a substitute for checking the actual code.
The central skill is making the program's structure understandable. The number of files is less important than the fit between each file's purpose and its contents, and the clarity of the connections among files.
  • Check imports, defined names, and calls across the complete set of files.
  • Trace a representative input through the modules to verify the intended flow.
  • Revise unclear responsibilities instead of adding files without a reason.

Worked example

Move a calculation into a module

Organize a program that adds two numbers. The calculation should be in totals.py, and main.py should call it with 8 and 5. State the preconditions, input, steps, and expected output.
Two-file addition program
imports; calls with 8 anreturns 13main.py: call and displatotals.py: add_values

main.py imports totals.py, calls its function with two values, then displays the returned value.

Python 3

# totals.py
def add_values(first, second):
    return first + second

# main.py
import totals

result = totals.add_values(8, 5)
print(result)
  1. Assign responsibilities
    Place the addition function in totals.py. Let main.py import totals and coordinate the call. The preconditions are that both files are in the same folder and the function name in the call matches its definition.
  2. Trace the call
    The input values are 8 and 5. The main file calls totals.add_values with those values. The function adds them and returns 13; the coordinating file then displays that result. The expected output is 13.
Answer: The calculation belongs in totals.py, while main.py imports that module and displays the returned total.
Check: The function is defined in the imported module, and the function name used by main.py matches that definition.

Worked example

Separate a conversion task from program flow

A program receives a distance in kilometres and displays the equivalent number of metres. Put the conversion in distance_tools.py and the coordinating steps in main.py. Trace an input of 3.2 kilometres.
Distance conversion modules
imports; supplies 3.2 kmreturns 3200.0 mmain.py: supply input andistance_tools.py: conve

The main file supplies a kilometre value to the conversion module and displays its return value.

Python 3

# distance_tools.py
def kilometres_to_metres(kilometres):
    return kilometres * 1000

# main.py
import distance_tools

metres = distance_tools.kilometres_to_metres(3.2)
print(metres)
  1. Set the precondition and input
    Assume the input is a numeric distance measured in kilometres and the two files are together in the same folder. The input for this trace is 3.2. The conversion function expects a number and returns a numeric distance in metres.
  2. Follow the module connection
    main.py imports distance_tools and calls its conversion function with 3.2. The function multiplies by 1000, returns 3200.0, and main.py displays the returned value. The expected output is 3200.0. This is a trace from the code, not a report of an executed program.
Answer: Keep the conversion in distance_tools.py and let main.py handle the call and display.
Check: The called name must be defined in distance_tools.py, and the input must represent kilometres rather than metres.

Worked example

Find and correct a name mismatch

A project has a file named messages.py defining greet_user(name), but main.py imports messages and calls messages.greeting("Mina"). Identify the organization problem and give a corrected call. State the expected output if the function returns "Hello, " followed by the name.
Corrected greeting module connection
imports; calls greet_usereturns Hello, Minamain.py: call greet_usermessages.py: define gree

main.py imports messages.py and calls the function name defined in that module.

Python 3

# messages.py
def greet_user(name):
    return "Hello, " + name

# main.py
import messages

print(messages.greet_user("Mina"))
  1. Compare the names
    The module name messages matches the filename messages.py, so that connection is consistent under the stated same-folder precondition. The function is defined as greet_user, but the call asks for greeting. Those function names do not match.
  2. Correct and trace
    Call messages.greet_user("Mina") instead. The function receives Mina and returns the greeting text. The expected output is Hello, Mina. The function name and the call now refer to the same definition.
Answer: Replace the mismatched call with messages.greet_user("Mina").
Check: A correct module name does not fix an incorrect function name; check both parts of a qualified call.

Common mistakes and how to avoid them

Importing a file but calling a function name that is not defined in it.
Correction: Compare the called name with the function definition, including spelling and underscores.
Using the filename including .py as the module name in a basic import.
Correction: For a same-folder file such as totals.py, use import totals.
Splitting code into files without giving each file a clear responsibility.
Correction: Group related functions and make the coordinating role of the main file easy to see.
Assuming separate files automatically make the program modular and understandable.
Correction: Check that the modules are actually connected by clear imports and calls, and that each contains related code.

Lesson summary

  • A modular program organizes related code in separate files called modules.
  • Give each file a clear responsibility, and use descriptive filenames.
  • Import a module before calling a function it provides; check both module and function names.
  • Trace inputs from the coordinating file into a function and follow the returned result back.
  • Use a file map and a representative trace to review the organization.

Check your understanding

Question 1

In a same-folder Python 3 project, which import matches a file named scores.py?
  1. import scores
  2. import scores.py
  3. import score
  4. call scores.py
Show answer and explanation
import scores
The module name is the filename without the .py ending, so import scores matches scores.py.

Question 2

A file named display_tools.py defines show_total(value). Which call uses that module and function name consistently after import display_tools?
  1. display_tools.show_total(12)
  2. display_tools.total(12)
  3. display.show_total(12)
  4. display_tools.py.show_total(12)
Show answer and explanation
display_tools.show_total(12)
The qualified call uses the imported module name and the function name as it is defined.

Question 3

Which arrangement best demonstrates a clear division of responsibility?
  1. A calculation module contains related calculation functions, and the main file imports and calls them.
  2. Every function is placed in a different file, whether or not the tasks are related.
  3. A support module is imported but none of its functions are used.
  4. The main file calls a function name that does not appear in the imported module.
Show answer and explanation
A calculation module contains related calculation functions, and the main file imports and calls them.
Related functions have a suitable home, and the main file visibly coordinates their use.

Key terms

Module
A file containing program code that can be imported and used by another file.
Import
A statement that makes a module available to the current file.
Responsibility
The main task a file is intended to handle.
Precondition
A fact that must be true before a program step or function can be used as intended.

Continue through ICS4U

View the complete ICS4U Ontario Grade 12 Computer Science curriculum and lessons

About this lesson and its review

Published by DoAssignment. This reviewed lesson follows Ontario Grade 12 Computer Science (ICS4U), expectation A2.1. It is a study resource, not an official curriculum publication.

Before publication, content is checked for structure, mathematical or chemical notation, calculations, course boundaries, and readability. Errors can still occur, so corrections are welcomed.

Official curriculum reference

Report a correction or ask a question