Python Modules

Tutorial 25 of 65 · pythondeck.com Python course

A module is a .py file; a package is a directory containing modules (and historically __init__.py). Use import, from ... import and aliases (as). The if __name__ == "__main__": guard separates script mode from import mode.

Modules are how Python organises code into reusable units. A single .py file is a module; a package is a directory of modules (often with __init__.py). Clean imports keep startup fast, avoid circular dependencies, and make projects navigable for teammates and tools.

The if __name__ == "__main__": guard lets the same file act as a library when imported and as a script when executed directly. Understanding import mechanics prevents accidental side effects on import myapp.

import pkg vs from pkg import name vs import pkg as alias.

Packages, namespace packages, and __init__.py (optional in Python 3.3+).

Module search path: sys.path, virtual environments, and PYTHONPATH.

__name__, __file__, and the __main__ guard.

Relative imports inside packages: from . import sibling.

Circular imports: restructuring, lazy imports, or moving shared code to a third module.

Importing a module runs its top-level code once; results are cached in sys.modules. Heavy work at import time slows every consumer—defer I/O and configuration to functions or an explicit main().

The __all__ list documents the public API for from module import * (still rarely used in production). Explicit exports in __init__.py improve autocomplete and documentation.

For applications, a src layout (src/myapp/) plus installed package avoids accidentally importing from the wrong working directory. Tools like pip install -e . make local development predictable.

Circular imports between two modules that import each other at top level.

Side effects on import: opening files, connecting to databases, printing banners.

Relying on the current working directory instead of proper package installation.

Wildcard imports (from mod import *) that pollute namespaces and break static analysis.

Naming a script the same as a standard library module (e.g. random.py).

Structure projects as packages with clear boundaries and minimal __init__.py logic.

Use absolute imports in application code; reserve relative imports for intra-package links.

Guard script entry points with if __name__ == "__main__": and call main().

Document public API in __all__ or explicit re-exports; keep internals prefixed with _.

Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.

The program below demonstrates import. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# Example: Import
# Run in the REPL or save as a .py file and execute with python.
import math
from math import pi, sqrt
import math as m

print(math.cos(0), pi, sqrt(2), m.e)

This sample walks through custom module in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# greet.py
def hello(name):
    return f"hello {name}"

# main.py
from greet import hello
print(hello("ada"))

Here is a hands-on illustration of __main__ guard. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.

# Example: __main__ guard
# Run in the REPL or save as a .py file and execute with python.
def main():
    print("running as a script")

if __name__ == "__main__":
    main()

The program below demonstrates import styles. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# Modules are files; packages are folders with __init__.py
import math  # import whole module
print(math.sqrt(16))  # 4.0 via namespace
from datetime import datetime, timezone  # import names directly
now = datetime.now(timezone.utc)  # aware UTC timestamp
print(now.isoformat())  # ISO string
import json as js  # alias avoids name clash
payload = js.dumps({"ok": True})  # serialize dict
print(payload)  # JSON text
print(__name__)  # __main__ when run as script

This sample walks through module search in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# sys.path lists directories consulted for imports
import sys  # system-specific parameters
print(sys.path[0])  # first entry is script directory
print(len(sys.path))  # number of search locations
if "" in sys.path:  # empty string means cwd
    print("cwd on path")  # informational
import importlib  # dynamic import machinery
mod = importlib.import_module("math")  # load by string name
print(mod.pi)  # use module object
print(hasattr(mod, "tau"))  # check attribute existence

« Python Scope All tutorials Python Dates »