Python Import¶
See also Python importtime and Python standard library.
Implementation¶
In short, the built-in __import__ function (builtins.__import__) calls
the C function PyImport_ImportModuleLevelObject() which calls
importlib._bootstrap._find_and_load() if the module is not cached in
sys.modules.
The implementation is splitted in multiple files in C and Python code. Main files:
Lib/importlib/_bootstrap.py: frozen as_frozen_importlibLib/importlib/_bootstrap_external.py: frozen as_frozen_importlib_externalPython/import.c
The API is splitted in multiple parts:
importlib.machinery: internalsimportlib.util: public helper functionsprivate
_impextensionC API like
PyImport_ImportModuleLevelObject()
The importlib package was added to Python 3.1. In Python 3.3, the import machinery was rewritten based on the importlib package.
importlib concepts¶
Module finder (finder) with a
find_spec()method.sys.meta_pathis a list of importlib finders.Path hooks used by PathFinder:
sys.path_hookslist. Usually:[zipimport.zipimporter, importlib._bootstrap_external.FileFinder]. To be exact, the second one is a function which creates a FileFinder instance if a path a directory.Module loader (loader) with
create_module()andexec_module()methods. Example:importlib.machinery.SourceFileLoader.Module specification (spec):
importlib.machinery.ModuleSpecwhich has a loader.sys.path_importer_cacheused byPathFinder
IMPORT_NAME bytecode¶
In Python 3.13, import <name> is implemented in Python/bytecodes.c with
the IMPORT_NAME(name, fromlist, level) bytecode: it has a name argument
and two stack arguments: fromlist and level. Usually, fromlist is
None and level is equal to 0. The IMPORT_NAME bytecode calls
the ceval.c import_name() function:
Get
__import__function of thebuiltinsname (usually thebuiltinsmodule dictionary)Call
__import__(name, frame_globals, frame_locals, fromlist, level). There is a fast-path when__import__in the frame builtins is the built-in__import__function (if the function was not overriden): callPyImport_ImportModuleLevelObject(name, frame_globals, frame_locals, fromlist, level)directly.
Example:
>>> def f():
... import name
... return name
...
>>> dis.dis(f)
1 0 RESUME 0
2 2 LOAD_CONST 1 (0)
4 LOAD_CONST 0 (None)
6 IMPORT_NAME 0 (name)
8 STORE_FAST 0 (name)
3 10 LOAD_FAST 0 (name)
12 RETURN_VALUE
Built-in __import__() function¶
builtins.__import__() is implemented in Python/bltinmodule.c. It just
calls PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level).
PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level)¶
In short, call importlib._bootstrap._find_and_load(name) if the module is
not cached in sys.modules.
Function implemented in Python/import.c. Simplified explanation (look at
the implementation for details):
Get the module from
sys.modules. If the module is already cached: return it.Call
importlib._bootstrap._find_and_load(name).If
fromlistis a non-empty list (if it’s true), callimportlib._handle_fromlist(module, fromlist, import_func)whereimport_funcisbuiltins.__import__.
importlib _find_and_load()¶
In short:
Call the
find_spec()method of eachsys.meta_pathfinder. Use the first matching spec (notNone).module = loader.create_module(spec).sys.modules[name] = moduleloader.exec_module(module)
importlib._bootstrap._find_and_load(name, import_func) pseudo-code:
Call
spec = _find_spec(name, path)where path isNoneorparent_module.__path__.Call
module = module_from_spec(spec)Cache the module in
sys.modulesCall
spec.loader.exec_module(module), except for namespace packages which have no loader
importlib._bootstrap._find_spec(name, path, target=None) pseudo-code:
For each finder of
sys.meta_path, callfinder.find_spec(name, path, target).If a
find_spec()method result is notNone, return spec.
importlib._bootstrap.module_from_spec(spec) pseudo-code:
Call
spec.loader.create_module(spec)Call
_init_module_attrs(spec, module)which sets module attributes:__cached____file____loader____name____package____path____spec__
importlib.import_module(name, package=None)¶
Implemented in Lib/importlib/__init__.py, call
importlib._bootstrap._gcd_import(name[level:], package, level) which calls
importlib._bootstrap._find_and_load(). Similar to builtins.__import__()
function.
Load a namespace package¶
A namespace package has no __init__.py file.
Implemented in Lib/importlib/_bootstrap_external.py with PathFinder.
sys.meta_path[2] is an _frozen_importlib_external.PathFinder instance
Call PathFinder.find_spec(name, path=None, target=None):
Call
PathFinder._get_spec(name, sys.path, target=None):For each
sys.pathentry, getPathFinder._path_importer_cache(entry):FileFinderinstance. CallFileFinder.find_spec(name, target)method.If there is a match, store
spec.submodule_search_locationsIf there was at least one match, combine all
spec.submodule_search_locationsas a namespace_path and create aModuleSpecwith it which has no loader (None).
PathFinder._path_importer_cache(entry) uses sys.path_importer_cache.
Python startup¶
_PyBuiltin_Init()creates thebuiltinsmodule. Thebuiltinsmodule dictionary is stored ininterp->builtins._PyImport_InitCore()inPython/import.c:Imports the
_frozen_importlibfrozen module, known as “importlib”Call
bootstrap_imp(): create the_impextensionMock a
ModuleSpecobject asspecCall
create_builtin(tstate, name, spec): internal function of_imp.create_builtin(). It callsPyInit__imp()of_PyRuntime.imports.inittab(as the"_imp"entry).Call
exec_builtin_or_dynamic(mod)(_imp.exec_builtin()): callPyModule_ExecDef(mod)which callsimp_module_exec(mod): thePy_mod_execslot ofimp_module.m_slots.
Store the
_impextension insys.modulesCall
_frozen_importlib._install(sys, _imp)Set up the spec for existing builtin/frozen modules
Add
BuiltinImporterandFrozenImportertosys.meta_path
Call
_PyImport_InitExternal():Call
_frozen_importlib._install_external_importers():Import
_frozen_importlib_externalCall
_frozen_importlib_external._install(_frozen_importlib)Add FileFinder path hook to
sys.path_hookAdd FileFinder to
sys.meta_path
Import
zipimport.zipimporterand prepends it tosys.path_hooks
Frozen modules¶
Modules/config.cimplements_PyImport_Inittab: file generated fromModules/config.c.inbyModules/makesetup.Example of an entry:
{"_imp", PyInit__imp}.PyImport_Inittabis initialized to_PyImport_InittabPyImport_ExtendInittab()copiesPyImport_Inittabtoinittab_copy_PyRuntime.imports.inittab
Links¶
PEP 451 – A ModuleSpec Type for the Import System (2013, Python 3.4) by Eric Snow
Unravelling the import statement (January 2021) by Brett Cannon
If I were designing Python’s import from scratch (December 2015) by Brett Cannon