ReviseAlgo Logo

Modules & Packages

Creating Modules

Writing reusable Python modules with proper structure

Interview: Code organization and software design — tested in system design discussions

Last Updated: June 12, 2026 8 min read

A Python module is simply a .py file containing Python code — functions, classes, variables, and executable statements. Creating well-structured modules is fundamental to code organization, reusability, and maintainability.

Module Structure

  • Module file: Any .py file can be a module — just import it by filename (without .py)
  • Module name: Available as __name__ — equals "__main__" when run directly
  • __all__: List of public names — controls what from module import * exports
  • Module-level code: Runs on first import — use if __name__ == "__main__": guard for scripts

if __name__ == "__main__" Guard

  • When imported: __name__ equals the module's filename — guard block is skipped
  • When run directly: __name__ equals "__main__" — guard block executes
  • Purpose: Lets a file work as both a module (importable) and a script (runnable)

Module Search Path

Python searches for modules in: (1) built-in modules, (2) directories in sys.path. sys.path includes the script's directory, PYTHONPATH directories, and standard library paths. You can modify sys.path at runtime, but prefer proper package installation with pip.

Module Caching

  • Imported once: Python caches modules in sys.modules — subsequent imports return the cached version
  • Reloading: Use importlib.reload(module) to force re-execution (useful during development)
  • .pyc files: Python compiles modules to bytecode in __pycache__ for faster loading

Use Cases

Organizing utility functions into reusable modules

Creating dual-purpose files that work as both scripts and importable modules

Building internal libraries shared across multiple projects

Plugin architectures with dynamic module loading

Configuration modules with module-level constants

Common Mistakes

Not using if __name__ == "__main__" guard — module code runs on every import

Putting side effects at module level — import should not print, create files, or modify state

Not defining __all__ — makes it unclear what the public API is

Using mutable module-level variables — creates hidden shared state between importers

Forgetting that modules are cached — changes to .py files require reload() or restart