Module Scope and Namespaces
An import statement tells Python to find a module file, execute its code, and make its contents available to your program.
Try it: What import Really Does
What happens on import: Python checks sys.modules, searches sys.path in order (first match wins), creates the module object, runs its top level once, then binds a name — the module, one function, or an alias — in the importing namespace; plus packages, __name__ == "__main__", ModuleNotFoundError and ImportError.
How it works
- If the name is already in sys.modules, reuse that module object: its code does not run again.
- Otherwise search each sys.path entry in order (the script's folder first); the first match wins, none raises ModuleNotFoundError.
- Create an empty module object, store it in sys.modules, then run the file's top level once (its __name__ is the module name, so a __main__ guard is skipped).
- import m binds m to the module; import m as x binds x; from m import f binds only f (ImportError if m has no f).
- A package runs its __init__.py first; submodules are found on the package's __path__ and become attributes of the package.
Default run (19 steps): $ python main.py — sys.path starts as [/project, /venv/site-packages, /usr/lib/python3.12]: the script's folder, then site-packages, then the standard library. Only our own modules are shown in sys.modules below. … Done. Printed: helpers loaded, __name__ = helpers | Hi Ann | Hi Ann.
Simplified: A fixed virtual project (main.py, helpers.py, pkg/, a site-packages folder and a one-file stand-in for the standard library). Built-in and frozen modules, .pyc caching, relative imports and namespace packages are not modelled; only our own modules are listed in sys.modules.
Loading the simulation…
Importing Is a Process
An import statement is more than a request to use a name. It instructs Python to locate a module, load it, execute the code in the module, and make the module's contents available to the importing program. This search-and-execute process happens behind the scenes whenever a module is imported.
Following sys.path
For a module that is not built into Python, the interpreter searches directories listed in sys.path. Python checks those directories in a specific order. It stops at the first directory containing a matching module file and uses that file. The search therefore depends not only on which files exist, but also on where those files appear in the search order.
A Search-Order Example
Suppose a program requests a non-built-in module named reports, and two directories in sys.path contain a matching module file.
- 1First directory
Python checks the first directory in the relevant search order.
- 2First match
If that directory contains the requested module file, Python uses it immediately.
- 3Later directory
Python does not continue searching for another matching file after the first match.
The directory order in sys.path determines which matching module file is selected.
First Import and Later Imports
When Python finds a module, it executes the code in that module's body during initialization. Python then caches the loaded module in memory. If the same module is imported again later, Python returns the cached module instead of executing the module's initialization code again.
One Initialization, Multiple Imports
A program imports the same module twice during its execution.
- 1First import
Python locates the module, executes its code, and caches the loaded module.
- 2Second import
Python finds that the module is already loaded and reuses the cached module.
- 3Observed behavior
The module's initialization code is not executed a second time.
The module is initialized once, while later imports use the already loaded module.
Contents Inside a Module
A module provides a separate place for its contents. Importing makes those contents available to the program that performed the import. This separation is the useful idea behind module scope and namespaces: module-related names and definitions are associated with the module that supplies them, rather than being treated as if they were newly declared directly in every importing location.
Naming Conflicts
Common mistake Assuming Python can find every module without searching
What it looks likeTreating an import as if the requested module were automatically available everywhere
Why it failsFor non-built-in modules, Python searches directories listed in
sys.pathand uses the first matching file.Do this insteadThink of import as a locate, load, execute, and make-available process.
Common mistake Expecting a repeated import to reinitialize a module
What it looks likeAssuming the module's initialization code runs again every time the module is imported
Why it failsPython caches the module after its first import and reuses it on later imports.
Do this insteadExpect the module to be initialized once and its state to persist during the program's execution.
Common mistake Ignoring the order of sys.path
What it looks likeCreating a file with the same name as a standard-library module
Why it failsDepending on search-path order, Python might find the locally created file instead of the intended module.
Do this insteadUse distinctive names and remember that the first matching location wins.
When debugging an import-related problem, inspect the search path and consider every directory Python checks before the module you expected. Search order can explain why a module with an unexpected name or location was selected.
Practice the Trace
A non-built-in module is requested. The first directory in sys.path does not contain a matching file, but the second directory does. Explain which directory Python uses, whether it checks later directories, and what happens if the same module is imported again later.
Hints
- Follow the directories in
sys.pathin order. - The first matching file ends the search.
- Separate the first import from later imports.
- 1An import statement starts a locate-and-load process. For non-built-in modules, Python searches
sys.pathin order and stops at the first matching module file. The first import executes the module's initialization code and caches the loaded module. Later imports reuse that cached module without re-executing its code. The module's contents are kept associated with the module and made available to the importing program.
Key Takeaways
- Importing a module triggers a locate, load, execute, and availability process.
- Python searches
sys.pathin order for non-built-in modules and uses the first matching file. - A module's initialization code runs only during its first import.
- Later imports reuse the cached module, allowing module state to persist during the program's execution.
- Search-path order can cause naming conflicts when different files have the same module name.