Warm-up · Activity 1 of 7
// B5.1 · ~25 min · Beginner
Modules and imports
After this lesson you can split a program into main.py and a helpers.py module, import it in the right form, and keep script-only code behind if __name__ == "__main__":.
Lesson 1 of 5 in B5 Modules, files and errors
You will be able to
- Import a module or single names from it with import and from … import
- Split a program into main.py and a second file, guarding script code with if __name__ == "__main__":
- List what a module defines with dir() and explain where Python looks for a module
Predict · Activity 2 of 7
Predict before you read on. dir() with no argument lists the names defined in this file. What does this print?
from math import sqrt print(sqrt(25), "math" in dir())Practice · Activity 3 of 7
Fill in the keyword so that the name math refers to the whole math module.
____ mathmathPractice · Activity 4 of 7
This file is saved as main.py and run with python main.py. What does it print?
print("name is", __name__)Practice · Activity 5 of 7
Match each import to the name or names it gives you.
Brain teaser · Activity 6 of 7
Brain teaser. What does this print?
from math import pi pi = 3 import math print(pi, math.pi > 3)Apply · Activity 7 of 7
Mini-task, on your own computer. Create temperature.py with a function c_to_f(celsius) that returns celsius * 9 / 5 + 32, and a self-test under if __name__ == "__main__":. Then, in main.py in the same folder, import it and print a line such as 0 C = 32.0 F for 0, 20 and 100. Run both files.
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A main program and its helpers module
Two files sit side by side: helpers.py defines two text functions, and main.py imports them in both forms. helpers.py prints a line at the top level, so you can see when it runs, and keeps its self-test under the __main__ guard. Run main.py, then look at which of helpers.py’s lines appeared.
main.py
import helpers
from helpers import word_count
sentence = "modules keep programs tidy"
print(helpers.shout(sentence))
print("words:", word_count(sentence))
print("helpers.__name__ is", helpers.__name__)
print("__name__ here is", __name__)
print([name for name in dir(helpers) if not name.startswith("_")])
helpers.py
"""Small text helpers, imported by main.py."""
def shout(text: str) -> str:
return text.upper() + "!"
def word_count(text: str) -> int:
return len(text.split())
print("loading helpers")
if __name__ == "__main__":
# Runs only with: python helpers.py
print("self-test:", shout("hi"), word_count("a b c"))
Run it with
python main.pyOutput
loading helpers
MODULES KEEP PROGRAMS TIDY!
words: 4
helpers.__name__ is helpers
__name__ here is __main__
['shout', 'word_count']- loading helpers appears once, although main.py imports helpers twice: top-level code runs on the first import only.
- The self-test did not run, because helpers.py’s __name__ is "helpers" when it is imported.
- main.py uses helpers.shout with the module name, but word_count on its own, because it was imported with from.
- dir(helpers) also lists names such as __name__ and __doc__; the list comprehension drops everything starting with _.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Exercises
Exercise 1 of 2
Use the helpers module
helpers.py (the second tab) defines average(scores) and grade(score). Leave it as it is. In main.py, read one line of whole-number scores separated by spaces, then print average: and the average, and grade: and its grade. Use import helpers for average and from helpers import grade for grade. For 80 65 the output is average: 72.5 and grade: C.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
Start main.py with two lines: import helpers, then from helpers import grade.
Hint 2
After import helpers, average is reached through the module: helpers.average(scores). grade is called on its own: grade(mean).
Hint 3
print("average:", mean) puts a space between the label and the number for you.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
import helpers
from helpers import grade
scores = [int(word) for word in input().split()]
mean = helpers.average(scores)
print("average:", mean)
print("grade:", grade(mean))
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
# helpers.py, next to this file, defines average(scores) and grade(score).
# Import them, then print the average and the grade of the scores typed in.
scores = [int(word) for word in input().split()]
print("average:", 0)
test_main.py
from learnrun import run_main
def report(line):
return run_main(line + "\n").strip().splitlines()
def test_average_and_grade():
"""80 65 gives average 72.5 and grade C"""
got = report("80 65")
assert got == ["average: 72.5", "grade: C"], f"for 80 65 the program printed {got!r}"
def test_top_grade():
"""90 100 gives average 95.0 and grade A"""
got = report("90 100")
assert got == ["average: 95.0", "grade: A"], f"for 90 100 the program printed {got!r}"
def test_uses_helpers():
"""main.py imports helpers instead of copying its functions"""
with open("main.py", encoding="utf-8") as f:
source = f.read()
assert "import helpers" in source, "main.py has no line import helpers"
assert "from helpers import grade" in source, "main.py has no line from helpers import grade"
assert "def " not in source, "main.py defines its own function; use the ones in helpers.py"
helpers.py
"""Score helpers for main.py. Leave this file as it is."""
def average(scores: list[int]) -> float:
return sum(scores) / len(scores)
def grade(score: float) -> str:
if score >= 90:
return "A"
if score >= 75:
return "B"
if score >= 50:
return "C"
return "F"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyExercise 2 of 2
Make main.py importable
main.py defines greet(name), which uses shout from helpers.py, and then asks for a name and prints the greeting. The tests import main.py to call greet, and at that moment nothing may be read or printed. Move the input and print lines under if __name__ == "__main__": so they run only when main.py itself is run.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
When a test imports main.py, its __name__ is "main". When you run it, its __name__ is "__main__".
Hint 2
Add the line if __name__ == "__main__": at the bottom and indent the two lines below it by four spaces.
Hint 3
Leave the def where it is: the tests need greet to exist after the import.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
from helpers import shout
def greet(name: str) -> str:
return shout("hello, " + name)
if __name__ == "__main__":
name = input()
print(greet(name))
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
from helpers import shout
def greet(name: str) -> str:
return shout("hello, " + name)
name = input()
print(greet(name))
test_main.py
import contextlib
import importlib
import io
import sys
from learnrun import run_main
def import_main():
sys.modules.pop("main", None)
printed = io.StringIO()
saved = sys.stdin
sys.stdin = io.StringIO("")
try:
with contextlib.redirect_stdout(printed):
module = importlib.import_module("main")
finally:
sys.stdin = saved
return module, printed.getvalue()
def test_import_is_quiet():
"""Importing main.py reads no input and prints nothing"""
try:
_, printed = import_main()
except EOFError:
assert False, "importing main.py called input(): move it under if __name__ == \"__main__\":"
assert printed == "", f"importing main.py printed {printed!r}: move the print under if __name__ == \"__main__\":"
def test_greet():
"""greet(\"ada\") returns HELLO, ADA!"""
try:
module, _ = import_main()
except EOFError:
assert False, "main.py could not be imported: it called input() at the top level"
got = module.greet("ada")
assert got == "HELLO, ADA!", f"greet(\"ada\") returned {got!r}, expected 'HELLO, ADA!'"
def test_run_as_script():
"""Run as a script, it still asks for a name and greets it"""
got = run_main("Grace\n").strip()
assert got == "HELLO, GRACE!", f"for Grace the program printed {got!r}, expected 'HELLO, GRACE!'"
helpers.py
"""Text helpers for main.py. Leave this file as it is."""
def shout(text: str) -> str:
return text.upper() + "!"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyCommon mistakes
Writing the file name in the import
import math.py
print(math.sqrt(16))
What Python prints
ModuleNotFoundError: No module named 'math.py'; 'math' is not a packageWhy, and the fix
import takes a module name, not a file name. Python reads math.py as "the module py inside the package math", which does not exist. Write import math, or import helpers for your own helpers.py.
Using the module name after from … import
from math import sqrt
print(math.sqrt(16))
What Python prints
NameError: name 'math' is not defined. Did you forget to import 'math'?Why, and the fix
from math import sqrt defines only sqrt, not math. Either call sqrt(16) directly, or change the import to import math and keep math.sqrt(16). Pick one form per module and use it consistently.
Calling a function without its module name
import math
print(sqrt(16))
What Python prints
NameError: name 'sqrt' is not definedWhy, and the fix
import math binds only the name math. Its functions stay inside it: write math.sqrt(16). If you want the short name, import it: from math import sqrt.
Python in the browser: Pyodide 314.0.7, MPL-2.0. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.