Chapter 8
Modules and the Standard Library
Every function you've written so far lived in the same file you were working in. Python also ships with a large collection of ready-made tools you didn't have to write, called the standard library. This chapter is how to reach for them, plus one idiom you'll see at the top of nearly every real Python script.
import
A module is a file of Python code, .py or built in, whose names you can
bring into your own script with import:
import math
print(math.sqrt(16))
4.0import math makes the whole math module available under the name
math; you reach its contents with a dot, math.sqrt. from ... import ...
brings in one specific name directly, so you don't need the dot each time:
from math import sqrt
print(sqrt(16))
4.0Either style works; this book mostly uses import module_name and the dot,
because it's clearer at a glance which module a name like sqrt came from.
A short tour
Three modules from the standard library, each with one clear job for this book's tracker.
math, for rounding a total up or down:
import math
total = 57.35
print(math.floor(total))
print(math.ceil(total))
57
58math.floor() rounds down, math.ceil() rounds up, both always toward the
nearest whole number in that direction.
statistics, for a quick average:
import statistics
amounts = [4.50, 12.00, 32.10, 8.75]
print(statistics.mean(amounts))
14.3375statistics.mean() does the same job as the average() function you may
have written in Chapter 7's practice, built in and ready to use.
random, for picking one entry to spot-check:
import random
expenses = [
{"amount": 4.50, "category": "coffee", "note": ""},
{"amount": 12.00, "category": "transit", "note": ""},
{"amount": 32.10, "category": "groceries", "note": ""},
{"amount": 8.75, "category": "coffee", "note": ""},
]
random.seed(7)
chosen = random.choice(expenses)
print(chosen)
{'amount': 32.1, 'category': 'groceries', 'note': ''}random.choice() picks one item from a list at random. random.seed(7)
above makes that "random" choice repeatable, which is the only reason this
example can be tested at all: with the same seed, random.choice() always
makes the same pick. You won't normally seed it in a real script; it's shown
here so the book's own claim, that every example was run and this is really
what it printed, still holds for a module whose whole point is
unpredictability.
datetime, for working with a date:
import datetime
started = datetime.date(2026, 9, 11)
print(started)
print(started.strftime("%B %d, %Y"))
2026-09-11
September 11, 2026datetime.date(2026, 9, 11) builds a specific date, year first, matching
how you'd read it out loud least ambiguously. .strftime() formats it as
text; %B is the full month name, %d the day, %Y the four-digit year.
You'll meet datetime.date.today() in other people's code for "the date
right now," left out of this book's own tested examples on purpose: a
result that depends on today's date is exactly the kind of thing that can't
be checked against a fixed expected answer, which every example in this
book is.
sys.argv, a preview
input() isn't the only way a script can receive information from whoever
runs it. sys.argv holds whatever was typed after the script's name on the
command line, as a list of strings:
import sys
print(sys.argv)
$ python show_args.py coffee 4.50
['show_args.py', 'coffee', '4.50']sys.argv[0] is always the script's own name; everything after it is
whatever the person typed. This is how a script can be run non-interactively,
python track.py coffee 4.50, instead of pausing for input() each time,
which matters the moment you want to run a script from another program or a
scheduled task rather than by hand. Turning that list of strings into a
proper set of named options, with help text and error messages of its own,
is a job for the argparse module, which is its own short subject and not
one this book covers.
Reaching for a module you haven't met
Not every module gets a mention here; the standard library has dozens. The habit that matters more than memorizing any particular one: when you need to do something that feels like it should be common, search "python" plus what you're trying to do before writing it from scratch. A surprising amount of everyday programming is already solved in a module you just haven't met yet.
name and the main-guard
Every module, including the file you're running directly, has a __name__.
Run a file directly and its __name__ is "__main__":
print(__name__)
__main__That's a plain fact about the file you're currently in, not something
special about this book: any script you run directly, python track.py,
has __name__ equal to "__main__" for the whole time it runs. The useful
part is what happens when a file is imported instead of run directly. In
that case, its __name__ becomes the module's own name, not "__main__".
That difference is exactly what if __name__ == "__main__": checks for.
It's the single most-asked "why is Python code written this way" question
there is, and it's worth understanding, not just copying. Picture two files:
# tools.py
def add_expense(expenses, amount, category, note=""):
expenses.append({"amount": amount, "category": category, "note": note})
return expenses
if __name__ == "__main__":
print("Run tools.py directly to see this.")
# track.py
import tools
expenses = []
tools.add_expense(expenses, 4.50, "coffee")
print(expenses)
Run python tools.py directly and its __name__ is "__main__", so the
guarded line runs and you see the message. Run python track.py, which
imports tools.py rather than running it directly, and tools.py's
__name__ is "tools", so the guarded line never runs, only
add_expense() gets used. The guard lets one file be both a reusable module
and a runnable script, without the "runnable script" part firing every time
someone else imports it. From Chapter 11 onward, this book's own script uses
exactly this pattern.
Practice
Try each of these before you read the solution under it.
- Use
mathto print the floor and the ceiling of19.20. - Given
amounts = [4.50, 12.00, 32.10, 8.75, 45.00], print the mean withstatistics.mean(). - Explain, in a comment above a bare
print(__name__), what it would print if this exact line lived in a file calledhelpers.pythat got imported by another script, versus run directly. Then show what it actually prints when run directly, right here. - Build
datetime.date(2026, 1, 15)and print it formatted as"January 15, 2026"using.strftime().
Solutions
1.
import math
print(math.floor(19.20))
print(math.ceil(19.20))
19
202.
import statistics
amounts = [4.50, 12.00, 32.10, 8.75, 45.00]
print(statistics.mean(amounts))
20.473. Imported, it would print "helpers"; run directly, it prints
"__main__", which is what this fence, run directly as part of the book's
own build, actually shows.
# imported by another script: would print "helpers"
# run directly: prints "__main__"
print(__name__)
__main__4.
import datetime
d = datetime.date(2026, 1, 15)
print(d.strftime("%B %d, %Y"))
January 15, 2026Where this leaves you
You can import a module and use a few useful ones from the standard
library, and you understand what __name__ is and why
if __name__ == "__main__": exists, not just what it looks like. Chapter 9
puts real data on disk: reading and writing a text file.