Lesson 2 of 8
A module isn't special — any .py file is a module. Save functions in helpers.py and any
other file can import helpers.
Creating one
Say greetings.py contains:
GREETING = "Hello"
def greet(name):
return f"{GREETING}, {name}!"
def farewell(name):
return f"Goodbye, {name}."
Another file in the same folder uses it:
import greetings
print(greetings.greet("Ada"))
print(greetings.GREETING)
The module name is the filename without .py. Functions, classes, and variables all come along.
Seeing it work here
The lessons run in a browser, so there's no folder of files to point at. But you already know how to create files — Module 6 — so we can write a module and import it in the same program:
import sys
with open("greetings.py", "w") as f:
f.write('GREETING = "Hello"\n\n')
f.write('def greet(name):\n')
f.write(' return f"{GREETING}, {name}!"\n')
sys.path.insert(0, "")
import greetings
print(greetings.greet("Ada"))
print(greetings.GREETING)
sys.path.insert(0, "") puts the current directory first on the search path from lesson 7.1.
You wouldn't normally write this — in a real project the files simply sit next to each other —
but it makes the mechanism visible.
Why split files at all?
Once a script passes a few hundred lines, one file becomes hard to navigate. Splitting gives you:
- Findability — validation logic lives in
validation.py, not somewhere in a 900-line file. - Reuse — the same
helpers.pyserves several programs. - Testability — Module 9's tests import your functions directly.
- Smaller diffs — two people can work on different files without conflicts.
Group by responsibility, not by type. storage.py, validation.py, reporting.py beat
functions.py, classes.py, stuff.py.
if __name__ == "__main__"
Here's a problem. Code at the top level of a module runs on import:
import sys
with open("tools.py", "w") as f:
f.write('def double(x):\n return x * 2\n\n')
f.write('print("tools.py is running!")\n')
sys.path.insert(0, "")
import tools
print(tools.double(5))
Importing tools printed its message — probably not what you wanted. Python sets a variable
called __name__ in every module:
- Run the file directly →
__name__is"__main__" - Import it →
__name__is the module name, e.g."tools"
So guard anything that should only happen when the file is run directly:
def double(x):
return x * 2
if __name__ == "__main__":
print("Testing:", double(5))
Now importing tools gives you double silently, while running python tools.py executes the
test code. You'll see this in almost every real Python file.
Modules are cached
Python imports a module once per program run, then reuses it:
import sys
with open("counter_mod.py", "w") as f:
f.write('print("loading...")\nvalue = 42\n')
sys.path.insert(0, "")
import counter_mod
import counter_mod
print(counter_mod.value)
"loading..." appears once even though there are two imports. That's why imports are cheap to
repeat, and why editing a module mid-session doesn't take effect until you restart.
Try it yourself
Write a module to a file, import it, and use it.
Notice "only when run directly" never printed — the __main__ guard did its job.
Checkpoint
- Any
.pyfile is a module;import filename(without the extension) loads it. - Split by responsibility once a file gets long.
- Top-level code runs on import — guard it with
if __name__ == "__main__":. __name__is"__main__"when run directly, otherwise the module's name.- Each module is imported and executed only once per run.
Questions about this lesson
Log in to ask a question.