Imports search sys.path via finders, then cache in sys.modules
When you write import foo, Python first checks sys.modules, the cache of already-imported modules. If foo is not there, it iterates sys.meta_path, a list of finder objects. The default finders handle built-in modules, frozen modules, and the path-based finder, which searches the directories listed in sys.path. sys.path is a list of strings initialized from the script directory or the current directory, then PYTHONPATH, then the standard library paths, then site-packages. The first matching module wins, so order matters. Once a finder returns a spec, the loader creates the module object, executes its code, and stores it in sys.modules. Subsequent imports reuse the cached module. This is why editing a module after import does not take effect without a reload, and why naming a local file json.py can shadow the standard library json module and break unrelated code.
sys.modules: cache of imported modules. Checking it first avoids re-executing module code.
sys.meta_path: list of finders. The default includes BuiltinImporter, FrozenImporter, and PathFinder.
sys.path: search path for the PathFinder. Modify with care; changes affect all subsequent imports.
Relative imports (from . import x) work only inside packages and resolve against package.
init.py runs before submodules are imported, so it affects the package namespace.
Common mistake: naming a module after a stdlib module, which shadows it and causes confusing failures.
Common mistake: relying on the current working directory being on sys.path in production. It is not in many deployment contexts.
Version note: the import system is defined by PEP 302 and refined by later PEPs. The finder/loader protocol is stable in Python 3.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience