Python Basics — Creating Modules

3 minute read

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 with import module. It doesn’t update names imported with from 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 .py file is a module — import it with import filename (without .py)
  • Module-level variables, functions, and classes are all importable
  • Use __all__ to control what from module import * exports
  • Use _prefix for 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 →

Updated: