25. Modules and import — Homework solutions
Each problem has its own folder under
exercises/25/homework/solutions/. To run one:
cd exercises/25/homework/solutions/01-greet-module
python main.py
Problem 1 — Greet module
Problem. Finish a greet.py module
exposing hello and bye.
How to think about it. A plain .py file
with two functions — no wrapper needed. Both are tiny: one
print each.
Worked solution. greet.py:
def hello(name):
print(f"Hello, {name}!")
def bye(name):
print(f"Goodbye, {name}.")main.py:
import greet
greet.hello("Keiko")
greet.bye("Keiko")Common mistakes.
- Adding
if __name__ == "__main__":guards in the module and calling the functions there. The module should only define functions; the caller does the calling. - Running from the wrong directory.
cdinto the folder first, or Python will not findgreet.py.
Problem 2 — Math helpers
Problem. A module with double and
triple.
How to think about it. Same shape as Problem 1, but the functions return values instead of printing. The caller does the printing.
Worked solution. math_helpers.py:
def double(x):
return x * 2
def triple(x):
return x * 3main.py:
import math_helpers as mh
print(mh.double(7)) # 14
print(mh.triple(7)) # 21
print(mh.double(mh.triple(5))) # 30Common mistakes.
- Putting
printinside the module functions. Returning values lets the caller decide what to do with them.
Problem 3 — Counter
Problem. A module with increment,
get, and reset. The internal counter must
persist across calls.
How to think about it. A variable at module level
(outside any function) lives for the module's lifetime — which, thanks
to Python's import caching, is the whole program's lifetime. All three
functions read and modify that same variable. Functions that assign to a
module-level variable must declare it with global.
Worked solution. counter.py:
_count = 0
def increment():
global _count
_count = _count + 1
def get():
return _count
def reset():
global _count
_count = 0main.py:
import counter
counter.increment()
counter.increment()
counter.increment()
print(counter.get()) # 3
counter.reset()
print(counter.get()) # 0Common mistakes.
- Declaring
countinsideincrement. Every call resets it to0, then bumps it to1. Persistent state must live at module level, outside the function. - Forgetting
global _countinsideincrementandreset. Without it, Python creates a local variable that shadows the module-level one; the module-level value never changes.
Challenge — String utilities
Problem. A module with three string functions of your own design.
How to think about it. Pick three. The example shows
shout, echo, and reverse_words.
reverse_words splits on whitespace with
.split() and reverses the resulting list.
Worked solution. string_utils.py:
def shout(s):
return s.upper() + "!"
def echo(s, n):
return " ".join([s] * n)
def reverse_words(s):
words = s.split()
words.reverse()
return " ".join(words)main.py:
import string_utils as su
print(su.shout("hello")) # HELLO!
print(su.echo("hi", 4)) # hi hi hi hi
print(su.reverse_words("one two three four")) # four three two ones.split() with no argument splits on any whitespace and
returns a list of words. [s] * n creates a list of
n copies of s. " ".join(...)
joins them with spaces.
Common mistakes.
- Writing
s.split(" ")instead ofs.split(). The no-argument form handles multiple spaces and leading/trailing whitespace cleanly; the single-space form does not.
Done?
Part 5 is finished once the four homework programs run. The Part 5 mini-project — a Text Adventure — combines functions, lists, dictionaries, and modules into a tiny game world.