Modules & Packages
Any .py file is a module that other code can import. A folder of modules is a package. Splitting a program into modules keeps each file focused, and the import system is also how you use the standard library and third-party packages.
Importing
import math from random import choice, seed from datetime import date as Date import statistics as stats print(math.sqrt(16), math.pi.__round__(3)) seed(1) print(choice(["red", "green", "blue"]) in {"red", "green", "blue"}) print(Date(2026, 1, 1).year) print(stats.mean([2, 4, 9]))
4.0 3.142 True 2026 5
| Form | Use as |
|---|---|
import math | math.sqrt(16) — clear where every name comes from |
from math import sqrt, pi | sqrt(16) — shorter, for a few frequently used names |
import numpy as np | An alias, often a community convention |
from math import * | Imports everything — avoid; it hides where names come from |
Writing your own module
Create a file called geometry.py:
"""Simple geometry helpers.""" PI = 3.14159 def circle_area(radius): return PI * radius ** 2 def _validate(value): if value < 0: raise ValueError("must be non-negative")
Then, from another file in the same folder:
import geometry from geometry import circle_area print(geometry.PI) print(circle_area(2))
A leading underscore (_validate) signals that a name is internal to the module — it still can be imported, but it isn't part of the public interface, and from geometry import * skips it.
Modules run once
The first import of a module runs its top-level code and caches the result in sys.modules. Later imports anywhere in the program reuse the same module object. That makes modules a natural place for shared configuration — but also means top-level code should only define things, not do heavy work.
if __name__ == "__main__"
Each module has a __name__. It's "__main__" when the file is run directly, and the module's name when it's imported. This lets a file work both as a script and as an importable module:
def celsius_to_f(c): return c * 9 / 5 + 32 def main(): for c in (0, 37, 100): print(f"{c}°C = {celsius_to_f(c)}°F") if __name__ == "__main__": main()
0°C = 32.0°F 37°C = 98.6°F 100°C = 212.0°F
Running python3 temps.py prints the table; import temps from another file just gives access to celsius_to_f without printing anything.
Packages
A package is a folder of modules. A typical project layout:
shop/
├── pyproject.toml
├── src/
│ └── shop/
│ ├── __init__.py
│ ├── cart.py
│ ├── pricing.py
│ └── payments/
│ ├── __init__.py
│ └── stripe.py
└── tests/
└── test_cart.py
# absolute imports (preferred) from shop.cart import Cart from shop.payments.stripe import charge # inside shop/cart.py, a relative import of a sibling module from .pricing import apply_discount
__init__.py runs when the package is imported and can re-export the most important names, so users can write from shop import Cart. It can be empty.
Where Python looks for modules
import sys for folder in sys.path: print(folder)
Python searches the script's own folder first, then the standard library, then installed third-party packages (site-packages). A common bug: naming your own file random.py or json.py — it shadows the standard-library module of the same name, and imports start behaving strangely.
Exploring a module
import math print([name for name in dir(math) if not name.startswith("_")][:8]) print(math.__name__) print(math.hypot.__doc__.splitlines()[0])
['acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'cbrt'] math Multidimensional Euclidean distance from the origin to a point.
dir(module) lists its names and help(module) shows its documentation — handy in the interactive shell.
The standard library
Python ships with hundreds of modules. Some you'll use often:
| Module | For |
|---|---|
pathlib, shutil, os | Files and folders (lesson 44) |
json, csv, tomllib, sqlite3 | Data formats and a built-in database |
datetime, zoneinfo, time | Dates and times (lesson 49) |
math, random, statistics, decimal | Numbers (lesson 48) |
re | Regular expressions (lesson 50) |
collections, itertools, functools | Data structures and functional tools |
logging, argparse, subprocess | Building command-line tools |
urllib.request, http.server, asyncio | Networking and concurrency |
unittest, doctest | Testing (lesson 53) |