Every interesting Python file you will ever read starts with import statements, and until today you have been typing them on faith. This lesson removes the faith. You will learn what a module actually is, how to split your own code across files, what packages and pip are, and then take a guided tour of the standard library, the enormous collection of modules that ships inside Python itself. The language's famous slogan is batteries included, and this is the lesson where you open the battery compartment.
The tour is deliberately practical. Rather than cataloging hundreds of modules, we visit the seven you will use weekly, math and random, datetime, collections, pathlib, os, and a glimpse of json ahead of Part 11, each with the three or four functions that carry most of their value. The goal is not memorization but geography: knowing what exists and where, so that next month, facing a real problem, you reach for the built-in tool instead of reinventing it badly.
What you will learn in Part 8
- What import really does, and the three import styles
- Writing your own modules and the __name__ == "__main__" idiom
- Packages, pip, and virtual environments in five honest minutes
- math, random, and datetime for numbers, chance, and time
- collections.Counter and defaultdict, the dict upgrades
- pathlib for files and folders that work on every OS
Note
Before you start
You need functions from Part 4, collections from Part 5, and files from Part 7. Everything in the tour runs in the playground, including the pathlib examples, which use the in-browser file system.
1. What import actually does
A module is simply a Python file. When you write import math, Python finds the file, runs it once, top to bottom, and binds the resulting namespace to the name math; every function and variable defined in that file is now reachable through the dot. Run import math again and nothing re-executes, because Python caches loaded modules. That is the entire mechanism, and it explains the three import styles you will see in the wild: import the module and use qualified names, import specific names from it, or rename on arrival with as.
import math # qualified: clearest for readers
print(math.sqrt(225)) # 15.0
from math import pi, ceil # direct names: fine for a few favorites
print(ceil(pi)) # 4
import datetime as dt # rename: common for long module names
print(dt.date.today().year)
Style guidance you can trust for the rest of your career: prefer the qualified form for anything ambiguous, import a handful of names directly when they are unmistakable, and never write from module import *, which dumps unknown names into your file and makes the next reader guess where anything came from. Imports live at the top of the file, standard library first, installed packages second, your own modules third, with a blank line between groups; it is the first thing reviewers look at, purely from habit.
2. Your own modules and the main guard
Splitting your code across files is the same mechanism in reverse. Put related functions in helpers.py, and any file in the same folder can import helpers and use helpers.tax_due(). The wrinkle every learner hits: importing a file runs it, including its test prints. The fix is the most famous idiom in Python. The interpreter sets the special variable __name__ to "__main__" only in the file you actually ran; in imported files it holds the module's name. Guarding your script-only code behind that check makes every file safely importable and runnable at once.
# helpers.py
def tax_due(income):
return income * 0.12
def main():
print(f"demo: {tax_due(1_000_000):,.0f}")
if __name__ == "__main__":
main() # runs only via: python3 helpers.py
# silent when another file does: import helpers
A package is the next size up: a folder of modules. Where modules organize functions, packages organize modules, and the import syntax just grows dots: from myproject.billing import tax. The third-party world works identically; pip install requests downloads a package from the Python Package Index into your environment, and from then on import requests works like any other import. The professional habit that goes with pip is the virtual environment, a per-project folder of installed packages created with python3 -m venv .venv, so projects cannot fight over versions. When you finish this track, the modern Python setup guide with uv in our advanced series shows the current state of the art for project tooling.
Checkpoint
A file you import prints test output you did not ask for. What is the standard fix?
3. The tour, stop one: math, random, and datetime
math holds the functions arithmetic forgot: square roots, logarithms, trigonometry, constants pi and e, plus floor and ceil. random supplies controlled chance: random() for a float between 0 and 1, randint for dice, choice to pick from a sequence, shuffle and sample for lotteries and quizzes; the Password Generator mini project in the Learn Python app is built almost entirely from random.choice over character sets. datetime handles the genuinely hard domain of time: today's date, precise moments, and arithmetic with timedelta, so questions like how many days until the exam become subtraction.
import math, random
from datetime import date, timedelta
print(math.sqrt(2) * math.pi) # numbers beyond arithmetic
print(random.randint(1, 6)) # a die roll
print(random.choice(["red", "green", "blue"]))
today = date(2026, 6, 13)
exam = date(2026, 7, 20)
print((exam - today).days, "days left") # 37 days left
print(today + timedelta(weeks=2)) # 2026-06-27
4. Stop two: collections, the dict upgrades
Remember the word-counting loop you built by hand in Part 5? The standard library was waiting for you to learn the principle first. collections.Counter counts any iterable in one call and answers the obvious follow-up with most_common. Its sibling defaultdict removes the missing-key dance entirely: tell it what to create on first access, and grouping records becomes a two-line loop. These two cover an absurd share of everyday data wrangling, and recognizing their use cases on sight is a small professional superpower.
from collections import Counter, defaultdict
words = "learn python by doing then doing more python".split()
counts = Counter(words)
print(counts.most_common(2)) # [('python', 2), ('doing', 2)]
students = [("A", "Amina"), ("B", "Zane"), ("A", "Ruwan")]
by_grade = defaultdict(list)
for grade, name in students:
by_grade[grade].append(name) # no key check needed, ever
print(dict(by_grade)) # {'A': ['Amina', 'Ruwan'], 'B': ['Zane']}
5. Stop three: pathlib and os, your file system passport
Part 7 opened files by bare name; real programs need to build paths, create folders, check existence, and walk directory trees, on Windows and Unix alike, where even the slash direction differs. pathlib solves all of it with one elegant object. A Path supports the slash operator for joining, knows its own name, stem, and suffix, can read and write itself in one call, and can glob for matching files. Its older companion os still owns environment variables and a few system facts, but for anything involving paths, pathlib is the modern answer and the only one this course uses.
from pathlib import Path
base = Path("project")
(base / "data").mkdir(parents=True, exist_ok=True)
report = base / "data" / "report.txt" # / joins paths on every OS
report.write_text("quarterly numbers\n") # open/write/close in one call
print(report.exists()) # True
print(report.suffix, report.stem) # .txt report
for p in base.rglob("*.txt"): # walk the whole tree
print(p, p.stat().st_size, "bytes")
That rglob line deserves a pause: it recursively visits every matching file under a folder, lazily, one at a time, no matter how huge the tree. The machinery making that possible, iterators, is exactly the subject of Part 9, and pathlib will be your first everyday beneficiary of understanding it. Meanwhile os.environ, a dict-like view of environment variables, is how real programs receive secrets and settings without hardcoding them, a practice that becomes critical in the deployment lessons of our advanced series.
One more everyday module rounds out the tour: sys, and specifically sys.argv, the list of command line arguments your script was started with. python3 report.py grades.txt 2026 puts those strings at argv[1] and argv[2], and suddenly your scripts take inputs without editing the code, the difference between a program you reuse and one you keep rewriting. For anything beyond two positional arguments, the stdlib's argparse builds proper interfaces with flags and help text, and it is exactly the upgrade to reach for when argv starts feeling cramped.
From loose script to tiny package, in five moves
gradebook.py has parsing functions, report functions, and the run-it code, all tangled in one file. It works, and it is getting harder to navigate every week.
gradebook.py (180 lines, everything)
Make a folder, move parsing into one module and reporting into another. Each file now has a single job and a name that says it.
gradebook/ parsing.py # read_grades(), clean_row() reporting.py # averages(), render_table()
An __init__.py file, even empty, tells Python the folder is importable. Modern Python can often manage without it, but adding it keeps every tool happy.
gradebook/ __init__.py parsing.py reporting.py
A new main.py imports from the package and holds only the top-level flow, guarded by the main idiom from section 2.
# main.py
from gradebook.parsing import read_grades
from gradebook.reporting import render_table
if __name__ == "__main__":
render_table(read_grades("grades.txt"))
python3 main.py runs the flow; any other project can now import gradebook.parsing without triggering it. The same structure scales from this toy to libraries with millions of users.
python3 main.py Amina 87 Zane 91 average: 85.0
Checkpoint
You need to count how many times each product appears in a list of 10,000 orders. The most Pythonic tool is:
6. Practice: a file organizer
The playground below builds a miniature version of a genuinely useful script: it creates a messy folder of files, then organizes them into subfolders by extension, counting as it goes with Counter. This is real automation, the kind people write to tame their downloads folder, scaled to the browser sandbox. The exercises extend it with datetime stamps and a dry-run mode, the safety feature every file-moving script should have.
! Common mistakes to avoid
-
✕Naming your file random.py or math.py and shadowing the standard library.
✓Your file wins the import race, and import random suddenly imports your script. If a stdlib module misbehaves, check your folder for a file with its name.
-
✕Building paths by gluing strings with + and forward slashes.
✓String paths break across operating systems. Path objects with the / operator handle separators, and read_text/write_text shrink three lines to one.
-
✕Installing packages globally for every project.
✓One project needs version 1, another needs version 2, and the fight breaks both. A virtual environment per project (python3 -m venv .venv) ends the problem permanently.
-
✕Writing from module import * in real code.
✓Star imports hide where names come from and can silently overwrite each other. Import the module, or the specific names you use, so every name has a visible origin.
? Frequently asked questions
How do I find out what a module offers without leaving Python? +
dir(module) lists its names and help(module.thing) prints the documentation. Combined with the official docs at docs.python.org, that is the complete reference workflow professionals actually use.
When should I pip install something instead of using the standard library? +
When the stdlib version costs you real effort: requests over urllib for HTTP is the classic example. But check the stdlib first; csv, json, sqlite3, and friends ship ready, and every dependency you skip is maintenance you avoid.
What is the difference between a module and a package? +
A module is one .py file; a package is a folder of modules (traditionally marked by __init__.py). Both are imported with the same syntax, packages just add dots: package.module.name.
Is __init__.py still required? +
Regular packages use it, and it is still the convention to include one, even empty. It can also run package setup code and define what import * would expose, though you now know not to use star imports anyway.
7. Recap and what comes next
Imports are no longer magic: modules are files run once and cached, packages are folders, pip and virtual environments manage the outside world, and your own code can be split cleanly with the main guard protecting script behavior. The tour gave you working geography of math, random, datetime, Counter, defaultdict, pathlib, and os.environ, the modules that earn their keep weekly in real work.
Next is the most intellectually satisfying lesson of the intermediate stretch: Part 9, iterators and generators, which explains the machinery behind every for loop you have written and teaches you to process unlimited data in constant memory with yield. The Modules and Collections lessons in the Learn Python app below add spaced-repetition quizzes, and the full track lives on the series hub.
Pro tip
Once a week, open the standard library index at docs.python.org and read the one-line descriptions of ten modules you have never used. Three months of that and you will know the warehouse better than most working developers, for the cost of a coffee break.
Practice on the go
Learn Python, the free Android app
Every topic in this series lives in the app too: bite-size lessons, runnable examples, quizzes, mini projects, and an offline Python playground that runs on your phone.
Comments
0No comments yet. Be the first to share your thoughts.