Modules & Packages
Modules & Packages
A module is simply a .py file. A package is a directory containing an __init__.py file (which may be empty) plus one or more modules. Python's module system lets you organise, reuse, and distribute code.
Importing
import math # import the whole module
from math import sqrt, pi # import specific names
from math import sqrt as square_root # rename on import
import numpy as np # common alias patternPrefer explicit imports (from module import name) over wildcard imports (from module import *) — wildcards pollute the namespace and make it hard to trace where names come from.
name == "main"
Every module has a __name__ attribute. When a script is run directly, __name__ equals "__main__". When imported, it equals the module's file name. This idiom protects code that should only run as a script:
# mymodule.py
def add(a, b):
return a + b
if __name__ == "__main__":
print(add(2, 3)) # only runs when executed directlyCreating a Package
mypackage/
__init__.py # marks the directory as a package
utils.py
models.pyfrom mypackage import utils
from mypackage.models import User__init__.py can re-export names for a cleaner public API:
# mypackage/__init__.py
from .utils import helper_function
from .models import UserKey Standard Library Modules
| Module | Purpose |
|---|---|
os | OS interaction: paths, env vars, processes |
sys | Interpreter state: argv, path, exit |
math | Mathematical functions and constants |
random | Pseudo-random numbers |
datetime | Dates and times |
pathlib | Object-oriented filesystem paths |
collections | Specialised containers (deque, Counter, defaultdict) |
itertools | Iterator building blocks |
functools | Higher-order functions (reduce, lru_cache, wraps) |
re | Regular expressions |
json | JSON serialisation |
csv | CSV file reading/writing |
logging | Flexible logging |
unittest | Test framework |
Code Examples
import math
import random
from datetime import datetime, timedelta
# math module
print("pi:", math.pi)
print("sqrt(144):", math.sqrt(144))
print("ceil(4.2):", math.ceil(4.2))
print("factorial(6):", math.factorial(6))
print("log2(1024):", math.log2(1024))
# random module
random.seed(42)
print("\nRandom int (1-10):", random.randint(1, 10))
print("Random choice:", random.choice(["apple", "banana", "cherry"]))
nums = list(range(1, 11))
random.shuffle(nums)
print("Shuffled:", nums)
# datetime module
now = datetime(2024, 6, 15, 9, 30)
print("\nNow:", now.strftime("%Y-%m-%d %H:%M"))
future = now + timedelta(days=30, hours=2)
print("In 30 days:", future.strftime("%Y-%m-%d %H:%M"))math provides precise mathematical functions. random.seed() makes results reproducible — essential for testing. datetime objects support arithmetic via timedelta, making date calculations natural.
import os
import sys
# os — operating system interface
cwd = os.getcwd()
print("Current directory:", cwd)
# Environment variables
path = os.environ.get("PATH", "not set")
print("PATH is set:", path != "not set")
# os.path utilities
sample = "/home/user/documents/report.txt"
print("Dirname: ", os.path.dirname(sample))
print("Basename:", os.path.basename(sample))
print("Splitext:", os.path.splitext(sample))
print("Join: ", os.path.join("/home/user", "docs", "file.txt"))
# sys — interpreter info
print("\nPython version:", sys.version[:6])
print("Platform:", sys.platform)
print("Executable:", sys.executable[:30], "...")os.path functions manipulate path strings without touching the filesystem. os.environ provides a dict-like interface to environment variables. sys gives access to interpreter internals like the Python version, loaded modules, and the command-line arguments.
from collections import Counter, defaultdict, deque
# Counter — count occurrences
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counter = Counter(words)
print("Counts:", dict(counter))
print("Top 2:", counter.most_common(2))
# defaultdict — dict with automatic default values
graph = defaultdict(list)
edges = [("A", "B"), ("A", "C"), ("B", "D"), ("C", "D")]
for src, dst in edges:
graph[src].append(dst)
print("\nGraph:", dict(graph))
# deque — efficient double-ended queue
dq = deque([1, 2, 3], maxlen=5)
dq.appendleft(0) # O(1) left append
dq.append(4) # O(1) right append
print("\nDeque:", dq)
dq.rotate(2) # rotate right by 2
print("Rotated:", dq)Counter is great for frequency analysis. defaultdict eliminates KeyError when building nested structures. deque with maxlen acts as a circular buffer, dropping the oldest item when full. All three are O(1) for their primary operations.
Quick Quiz
1. What is the purpose of if __name__ == '__main__':?
2. What makes a directory a Python package?
3. Which collections type is best for counting occurrences of items?
Was this lesson helpful?