Python Basics — Creating Modules
Creating Modules
Any Python file is a module. Creating your own modules lets you organize code into reusable, maintainable pieces.
Writing a Python Module
Create a file named mathtools.py:
# mathtools.py
"""A collection of math utility functions."""
PI = 3.14159
def add(a, b):
"""Return the sum of a and b."""
return a + b
def multiply(a, b):
"""Return the product of a and b."""
return a * b
def circle_area(radius):
"""Calculate the area of a circle."""
return PI * radius ** 2
Now use it from another file in the same directory:
# main.py
import mathtools
print(mathtools.add(3, 4)) # 7
print(mathtools.circle_area(5)) # 78.53975
print(mathtools.PI) # 3.14159
# Or import specific functions
from mathtools import add, circle_area
print(add(10, 20)) # 30
print(circle_area(10)) # 314.159
Module-Level Variables and Functions
Everything at the top level of a module file is accessible when imported:
# config.py
"""Application configuration."""
# Module-level variables (constants)
DATABASE_URL = "postgresql://localhost/mydb"
DEBUG = True
MAX_RETRIES = 3
VERSION = "1.0.0"
# Module-level functions
def get_connection_string(db_name):
return f"postgresql://localhost/{db_name}"
# app.py
import config
print(config.DATABASE_URL) # postgresql://localhost/mydb
print(config.DEBUG) # True
conn = config.get_connection_string("testdb")
print(conn) # postgresql://localhost/testdb
__all__ — Controlling Exports
The __all__ variable defines what gets exported when someone uses from module import *:
# utils.py
"""Utility functions."""
__all__ = ["public_function", "CONSTANT"]
CONSTANT = 42
def public_function():
"""This is exported."""
return "public"
def _private_helper():
"""Leading underscore = internal convention."""
return "private"
def another_function():
"""Not in __all__, so not exported by import *."""
return "another"
from utils import *
print(public_function()) # "public"
print(CONSTANT) # 42
# print(another_function()) # NameError — not in __all__
# print(_private_helper()) # NameError — not in __all__
# But explicit import still works:
from utils import another_function
print(another_function()) # "another"
Module Docstrings
The first string in a module file is its docstring:
# validators.py
"""
Input validation utilities.
Provides functions for validating emails, phone numbers,
and other user inputs.
Usage:
from validators import is_valid_email
assert is_valid_email("user@example.com") == True
"""
import re
def is_valid_email(email):
"""Check if an email address is valid."""
pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
return bool(re.match(pattern, email))
import validators
print(validators.__doc__)
# Input validation utilities...
help(validators)
# Full help output including docstrings
Reloading Modules
During development, you might edit a module and want to reload it without restarting Python:
import importlib
import mathtools
# Make changes to mathtools.py...
# Reload to pick up changes
importlib.reload(mathtools)
print(mathtools.add(1, 2)) # Uses updated code
Note:
importlib.reload()only works on modules imported withimport module. It doesn’t update names imported withfrom module import name.
Module Execution Guard
Always protect script-level code with the __name__ check:
# mathtools.py
"""A collection of math utility functions."""
PI = 3.14159
def add(a, b):
return a + b
def multiply(a, b):
return a * b
# This runs ONLY when mathtools.py is executed directly
if __name__ == "__main__":
# Test the functions
print(f"add(2, 3) = {add(2, 3)}")
print(f"multiply(4, 5) = {multiply(4, 5)}")
print("All tests passed!")
# Run directly — tests execute
python mathtools.py
# add(2, 3) = 5
# multiply(4, 5) = 20
# All tests passed!
# Import — tests don't execute
import mathtools
print(mathtools.add(2, 3)) # 5
# (No test output)
Best Practices for Modules
| Practice | Example |
|---|---|
| Use descriptive file names | validators.py, not v.py |
| Add module docstrings | """What this module does.""" |
Define __all__ for public API |
__all__ = ["func1", "func2"] |
Use _prefix for internal functions |
def _helper(): |
| Guard script code | if __name__ == "__main__": |
| Keep modules focused | One responsibility per module |
Summary
- Any
.pyfile is a module — import it withimport filename(without.py) - Module-level variables, functions, and classes are all importable
- Use
__all__to control whatfrom module import *exports - Use
_prefixfor internal/private functions (convention, not enforced) - Always add docstrings to modules and functions
- Use
if __name__ == "__main__":to guard test/script code - Use
importlib.reload()during development to reload changed modules
Next up: Packages & __init__.py →