A module is a single .py file; a package is a directory of modules. Imports let you use code from other modules, organizing a program into reusable pieces.
Modules and importing
(): a + b
PI =
# main.py — different ways to import
import math_utils # import the whole module
math_utils.add(2, 3) # access via the module name
from math_utils import add, PI # import specific names
add(2, 3) # use directly
from math_utils import add as plus # import with an alias
import numpy as np # common aliasing convention
mypackage/
__init__.py ← marks it as a package (can be empty)
module_a.py
subpackage/
__init__.py
module_b.py
from mypackage.module_a import something
from mypackage.subpackage.module_b import other
The __init__.py file marks a directory as a package (and can run package-init code or define what from package import * exposes).
if __name__ == "__main__" idiomdef main():
print("running as a script")
if __name__ == "__main__": # True only when run directly, not when imported
main()
This lets a file act as both an importable module and a runnable script — the code under it runs only when the file is executed directly (python file.py), not when imported. A near-universal Python idiom.
import sys
sys.path # the list of directories Python searches for imports
# includes: the current directory, installed packages (site-packages), stdlib
import os, json, datetime # standard library — "batteries included"
import requests # third-party — installed via pip from PyPI
Modules and packages are how you organize Python code into reusable, maintainable units rather than one giant file — fundamental to any non-trivial project.
Understanding the import styles, package structure (__init__.py), the if __name__ == "__main__" idiom (dual script/module behavior), and how Python finds modules (sys.path) is essential for structuring projects, reusing code, and using the vast standard library and PyPI ecosystem.
Import errors and structure confusion are common early hurdles that this knowledge resolves.