Modules and imports
Use Python's standard library instead of reinventing it.
Why it matters
Nobody writes AI software from scratch. The top of every AI script is a list of imports: json to read API replies, requests to call APIs, numpy for the math, the Anthropic SDK to talk to models. Once you know how imports work, and what Python's standard library already does, you reuse proven code instead of rewriting it. You can also read the first ten lines of any project and know what it depends on.
What you'll be able to do
- Import a module, or specific names from it, and use what it provides
- Use the standard library for math, randomness, dates, statistics and counting
- Explain what a module is and where Python looks for one
- Avoid the import mistakes that confuse beginners
What it covers
- Borrowing code with import
- A short tour of the standard library
- What a module really is
- Common import mistakes
- Worked example: a week of orders
- When an import goes wrong
Borrowing code with import
Think of a toolbox you borrow from a neighbor. You don't build a drill from scratch; you borrow one that already works. A module is that toolbox: a file of Python code, full of functions and values, that you can load into your program. Python ships with hundreds of them, called the standard library. Here's the math module:
import math print(math.sqrt(144)) print(math.ceil(4.2)) print(math.floor(4.8)) print(math.pi)
import math loads the module once. It gives you a name, math, to reach inside it with a dot: math.sqrt, math.pi. The dot means "the thing called sqrt that lives in math".
ceil rounds up and floor rounds down. That matters when you're working out how many batches, pages or boxes you need.
Three ways to import
import statistics from math import floor, ceil import datetime as dt print(statistics.mean([12, 18, 21])) print(floor(7.9), ceil(7.1)) print(dt.date(2026, 11, 27).strftime("%A"))
import statisticsbrings in the whole module. You writestatistics.meanevery time, which makes it obvious wheremeancame from.from math import floor, ceilbrings in specific names, so you writefloor(...)directly.import datetime as dtgives the module a shorter alias. Some aliases are universal conventions you'll see in every data and AI project:import numpy as np,import pandas as pd.
You may also meet from math import *, which dumps every name from the module into your program. Avoid it. Readers can no longer tell where a name came from, and it can silently replace your own variables.
from math import sqrt, which line works?Show the answer
sqrt(9)
from math import sqrt brings in the name sqrt only. The name math itself was never imported, so math.sqrt is a NameError.
A short tour of the standard library
random picks and shuffles. Setting a seed makes the "random" results repeatable. You'll do this constantly in machine learning, so experiments can be reproduced:
import random random.seed(7) subject_lines = ["Last chance", "New arrivals", "Your weekly picks"] print(random.choice(subject_lines)) print(random.randint(1, 100))
datetime handles dates and the gaps between them. A timedelta is a length of time:
from datetime import date, timedelta launch = date(2026, 11, 27) reminder = launch - timedelta(days=7) print("Launch:", launch) print("Send reminder on:", reminder) print("Days between:", (launch - reminder).days)
statistics covers the basics. Notice how the one big day pulls the mean up, while the median (the middle value when sorted) barely moves:
import statistics daily_signups = [42, 38, 51, 47, 39, 120, 44] print("mean:", round(statistics.mean(daily_signups), 1)) print("median:", statistics.median(daily_signups)) print("stdev:", round(statistics.stdev(daily_signups), 1))
For marketers: when a report shows an average order value, ask whether a few huge orders are inflating it. The median is often the more honest "typical" number.
collections.Counter counts things:
from collections import Counter sources = ["google", "newsletter", "google", "instagram", "google", "newsletter", "direct"] counts = Counter(sources) print(counts["google"]) print(counts["tiktok"]) print(counts.most_common(2))
most_common(2) returns the top two as pairs in parentheses, like ('google', 3). Those are tuples: fixed-size groups of values, like small lists that can't be changed. Asking a Counter for something it never saw gives 0 rather than an error.
import statistics print(statistics.median([10, 20, 30, 400]))
Show the answer
25.0
With an even number of values, the median is halfway between the middle two: 20 and 30 give 25.0. The mean would be 115, pulled up by the 400.
What a module really is
There's nothing special about a module: it's a .py file. Suppose a folder holds two files:
# metrics.py def roas(revenue, spend): if spend == 0: return 0 return revenue / spend
# report.py import metrics print(metrics.roas(15840, 3120.5))
Running report.py makes Python look for metrics.py, run it once, and give you its contents as metrics. Python searches for a module in this order:
- the folder of the script you're running,
- the standard library,
- third-party packages you've installed (the packages lesson covers installing them).
You'll often see this at the bottom of a script:
if __name__ == "__main__": main()
__name__ is "__main__" only when the file is run directly, not when it's imported. So this line means: "run main() when someone runs this file. Don't run it when another file imports this one to borrow its functions."
This explains the classic mistake: name your own file random.py and Python finds yours first.
Common import mistakes
The module isn't there. A typo, or a third-party package that isn't installed, gives a ModuleNotFoundError:
import maths
You named your file after a module. Save your own script as random.py or json.py, and import random will find your file first, because it's in the script's folder. The symptom is a baffling AttributeError, such as "module 'random' has no attribute 'choice'". Rename your file.
You forgot the prefix. After import math, plain sqrt(4) is a NameError. Write math.sqrt(4).
json.py, and import json then json.loads(...) fails with an AttributeError. Why?Show the answer
Python imported your own json.py from the script's folder instead of the standard library's
Python looks in the script's folder first, so your file hides the real module. Rename your file.
Worked example: a week of orders
Summarize a week of orders: count, average and median order value, the top traffic source, and how many days the data covers.
import statistics from collections import Counter from datetime import date order_values = [64, 28, 92, 18, 45, 64, 130, 22] order_sources = ["google", "email", "google", "instagram", "email", "google", "direct", "search"] first_order = date(2026, 11, 23) last_order = date(2026, 11, 29) top_source, top_count = Counter(order_sources).most_common(1)[0] print("Orders:", len(order_values)) print("Average order value:", round(statistics.mean(order_values), 2)) print("Median order value:", statistics.median(order_values)) print("Top source:", top_source, f"({top_count} orders)") print("Days covered:", (last_order - first_order).days + 1)
It reports 8 orders, an average of 57.88, a median of 54.5, google as the top source with 3 orders, and 7 days. The one big 130 order pulls the average above the median.
Three imports replace dozens of lines of hand-written counting, sorting and date arithmetic. most_common(1) returns a list holding one pair. [0] takes that pair, and top_source, top_count = ... unpacks it into two variables. The days calculation adds 1, because both the first and last day count.
When an import goes wrong
Three import problems account for nearly every confusing error here.
The two ways of importing give you different names. After import math, you write math.sqrt(9). After from math import sqrt, you write sqrt(9), and the name math doesn't exist. Mixing them gives a NameError, so check how the top of your file imported it.
You can hide a module by accident. If you save your own file as random.py or json.py, Python finds yours first, and the real module seems to have lost all its functions. If an import suddenly behaves strangely, look at your own file names.
Not everything needs installing. math, json, random and hundreds more come with Python. That's the standard library. Installing is only for outside packages, which you'll meet shortly. It's also why from module import * is best avoided: it pours in names from everywhere, and nobody reading the code can tell where they came from.
Practice what you just read
- 11 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 5 review cards for spaced repetition
Try a quiz question
You save a script as random.py. Inside it, import random then random.choice([1, 2]) fails with an AttributeError. Why?