Python Modules
Learn how Python modules work: create your own, import with aliases, use from-import, explore the standard library, and understand sys.path.
A module is a file containing Python code — functions, classes, and variables — that you can reuse across multiple programs. Modules are the basic unit of code organization in Python: instead of copying logic between files, you write it once, save it as a .py file, and import it wherever you need it. This chapter covers everything from creating your first module to navigating the standard library and understanding how Python locates modules at runtime.
What Is a Python Module?
Any .py file is a module. When you write:
# greetings.py
def hello(name):
return f"Hello, {name}!"
def goodbye(name):
return f"Goodbye, {name}!"
PI = 3.14159you have created a module named greetings. The module name is the filename without the .py extension.
Modules can contain:
- Functions — reusable blocks of logic (see Python Functions)
- Classes — blueprints for objects (see Python Classes)
- Variables and constants — shared data
- Executable statements — code that runs when the module is imported or executed directly
Importing a Module
Use the import statement followed by the module name (no .py extension).
import greetings
print(greetings.hello("Alice")) # Hello, Alice!
print(greetings.goodbye("Alice")) # Goodbye, Alice!
print(greetings.PI) # 3.14159After import greetings, all names defined in greetings.py are accessible through the greetings. prefix. This dot notation prevents name collisions — your own PI variable cannot clash with greetings.PI.
Importing Specific Names with from ... import
If you only need one or two names, import them directly so you can use them without the module prefix.
from greetings import hello, PI
print(hello("Bob")) # Hello, Bob!
print(PI) # 3.14159Importing Everything with *
from greetings import *This pulls every public name (those not starting with _) into the current namespace. Avoid it in larger programs: it pollutes the namespace and makes it hard to tell where a name came from.
Import Aliases with as
Long module names become tedious to type. Use as to create a shorter alias.
import greetings as gr
print(gr.hello("Carol")) # Hello, Carol!You can alias individual imported names too:
from greetings import hello as hi
print(hi("Dave")) # Hello, Dave!Aliases are especially common with popular libraries:
import numpy as np
import pandas as pd
import matplotlib.pyplot as pltThe dir() Function
dir(module) returns a sorted list of all names defined in a module — a fast way to explore what is available.
import math
print(dir(math))
# ['__doc__', '__loader__', ..., 'acos', 'acosh', 'asin', ..., 'sqrt', 'tan', 'tanh', 'tau']Call dir() with no arguments to see the names in the current scope.
The __name__ Variable
Every module has a built-in variable called __name__. When a file is imported, __name__ is set to the module name. When the file is run directly, __name__ is set to the string "__main__".
This pattern is the standard way to write code that runs only when the file is executed as a script — not when it is imported as a library:
# greetings.py
def hello(name):
return f"Hello, {name}!"
if __name__ == "__main__":
# This block only runs when you execute: python greetings.py
print(hello("World"))import greetings # The if-block does NOT run hereThis pattern is used in almost every non-trivial Python file you will encounter.
Module Search Path (sys.path)
When you write import greetings, Python searches for the module in a list of directories stored in sys.path:
- The directory of the script being run (or the current directory in interactive mode)
- Directories listed in the
PYTHONPATHenvironment variable - The standard library directories
- The
site-packagesdirectory (where third-party packages installed by pip live)
import sys
print(sys.path)
# ['/path/to/script', '/usr/lib/python3.11', ..., '/usr/lib/python3/dist-packages']You can append a path at runtime, but this is rarely needed for well-structured projects:
import sys
sys.path.append("/path/to/my/libs")The Python Standard Library
Python ships with a large standard library — hundreds of modules covering everything from file I/O to network protocols to data compression. You do not need to install anything; just import them.
math — Mathematical Functions
import math
print(math.sqrt(16)) # 4.0
print(math.pi) # 3.141592653589793
print(math.factorial(5)) # 120
print(math.ceil(4.2)) # 5
print(math.floor(4.8)) # 4See Python Math for a full reference.
random — Random Numbers
import random
print(random.randint(1, 10)) # random integer between 1 and 10
print(random.choice(["a", "b", "c"])) # random element
print(random.random()) # float in [0.0, 1.0)
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)
print(numbers) # shuffled in placedatetime — Dates and Times
import datetime
now = datetime.datetime.now()
print(now) # 2024-03-15 10:30:45.123456
print(now.year) # 2024
print(now.strftime("%B %d, %Y")) # March 15, 2024
today = datetime.date.today()
print(today) # 2024-03-15See Python Dates for full coverage of date arithmetic and formatting.
os and sys — Operating System and Interpreter
import os
print(os.getcwd()) # current working directory
print(os.listdir(".")) # files in the current directory
os.makedirs("new_dir", exist_ok=True) # create a directory
print(os.path.join("folder", "file.txt")) # 'folder/file.txt'import sys
print(sys.version) # Python version string
print(sys.platform) # 'linux', 'darwin', 'win32', etc.
sys.exit(0) # terminate the program with exit code 0json — JSON Encoding and Decoding
import json
data = {"name": "Alice", "age": 30, "active": True}
# Python → JSON string
json_string = json.dumps(data, indent=2)
print(json_string)
# JSON string → Python
parsed = json.loads(json_string)
print(parsed["name"]) # AliceSee Python JSON for file-based reading and writing.
collections — Specialized Data Structures
from collections import Counter, defaultdict
# Count occurrences
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counts = Counter(words)
print(counts) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(counts.most_common(2)) # [('apple', 3), ('banana', 2)]
# Dict with default values
scores = defaultdict(int)
scores["Alice"] += 10
scores["Bob"] += 5
print(dict(scores)) # {'Alice': 10, 'Bob': 5}See Python Collections Module for namedtuple, deque, and OrderedDict.
Creating Your Own Module
Basic Structure
Modules work best when they do one thing well. A good rule of thumb: if a group of functions share a theme, put them in their own file.
# mathutils.py
def clamp(value, minimum, maximum):
"""Restrict value to the range [minimum, maximum]."""
return max(minimum, min(value, maximum))
def average(numbers):
"""Return the arithmetic mean of a list of numbers."""
if not numbers:
raise ValueError("Cannot average an empty list")
return sum(numbers) / len(numbers)
def is_prime(n):
"""Return True if n is a prime number."""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True# main.py
from mathutils import clamp, average, is_prime
print(clamp(15, 0, 10)) # 10
print(average([2, 4, 6, 8])) # 5.0
print(is_prime(17)) # TrueDocstrings in Modules
Add a module-level docstring at the very top of the file. Tools like help() and documentation generators use it.
"""
mathutils.py — Utility functions for common mathematical operations.
Functions:
clamp(value, minimum, maximum) -> number
average(numbers) -> float
is_prime(n) -> bool
"""Module Variables: __all__
__all__ is a list of names that should be exported when someone does from module import *. It also serves as documentation about the module's public API.
# mathutils.py
__all__ = ["clamp", "average", "is_prime"]
def _helper(): # leading underscore marks it as private
passReloading a Module
Python caches imported modules in sys.modules. Importing the same module twice does not re-execute it — Python returns the cached version. During interactive development or debugging you can force a reload:
import importlib
import greetings
importlib.reload(greetings)This is mostly needed in REPL sessions or Jupyter notebooks after editing a module file.
Common Gotchas
Circular Imports
If module_a imports module_b and module_b imports module_a, you get a circular import. Python can handle some circular imports, but they are confusing and often indicate a design problem. The fix is usually to restructure your code — move the shared logic into a third module, or delay the import to inside a function.
Shadowing a Standard Library Module
If you name your file math.py, random.py, or json.py, you will shadow the standard library module and break any code that imports it. Use specific, descriptive names for your own modules.
# BAD: naming your file math.py shadows the stdlib
# GOOD: name it mathutils.py or geometry.pyImportError and ModuleNotFoundError
ModuleNotFoundError (a subclass of ImportError) means Python could not find the module anywhere on sys.path. Common causes:
- A typo in the module name
- The module is not installed (
pip install <package-name>) - The module file is in a directory not on
sys.path
try:
import nonexistent_module
except ModuleNotFoundError as e:
print(f"Import failed: {e}")
# Import failed: No module named 'nonexistent_module'Modules vs. Packages
A module is a single .py file. A package is a directory containing multiple modules and an __init__.py file. Packages let you build larger libraries with a hierarchical structure. See Python Packages for the full story.
Popular Third-Party Modules
Beyond the standard library, the Python ecosystem on PyPI has hundreds of thousands of packages. Install them with pip.
| Package | Purpose |
|---|---|
numpy | Numerical computing, multi-dimensional arrays |
pandas | Data analysis and manipulation |
matplotlib | Data visualization and plotting |
requests | HTTP requests made simple |
flask / django | Web frameworks |
scikit-learn | Machine learning algorithms |
pytest | Testing framework |