@@ -335,19 +335,29 @@ An import remains lazy only if the filter function returns ``True``.
335335
336336If no lazy import filter is set, all *potentially lazy * imports are lazy.
337337
338+ Lazy objects
339+ ------------
340+
341+ Lazy modules, as well as names lazy imported from modules, are represented
342+ by :class: `!types.LazyImportType ` instances, which are resolved to the real
343+ object (reified) before they can be used. This reification is usually done
344+ automatically (see below), but can also be done by calling the lazy object's
345+ ``get `` method.
346+
338347Lazy import mechanism
339348---------------------
340349
341350When an import is lazy, ``__lazy_import__ `` is called instead of
342351``__import__ ``. ``__lazy_import__ `` has the same function signature as
343352``__import__ ``. It adds the module name to ``sys.lazy_modules ``, a set of
344353fully-qualified module names which have been lazily imported at some point
345- (primarily for diagnostics and introspection), and returns a "lazy module
346- object."
354+ (primarily for diagnostics and introspection), and returns a
355+ :class: ` !types.LazyImportType` ` object for the module.
347356
348357The implementation of ``from ... import `` (the ``IMPORT_FROM `` bytecode
349358implementation) checks if the module it's fetching from is a lazy module
350- object, and if so, returns a lazy object for each name instead.
359+ object, and if so, returns a :class: `!types.LazyImportType ` for each name
360+ instead.
351361
352362The end result of this process is that lazy imports (regardless of how they
353363are enabled) result in lazy objects being assigned to global variables.
@@ -356,34 +366,36 @@ Lazy module objects do not appear in ``sys.modules``, they're just listed in
356366the ``sys.lazy_modules `` set. Under normal operation lazy objects should only
357367end up stored in global variables, and the common ways to access those
358368variables (regular variable access, module attributes) will resolve lazy
359- imports (" reify" ) and replace them when they're accessed.
369+ imports (reify) and replace them when they're accessed.
360370
361371It is still possible to expose lazy objects through other means, like
362372debuggers. This is not considered a problem.
363373
364374Reification
365375-----------
366376
367- When a lazy object is first used, it needs to be reified. This means resolving
368- the import at that point in the program and replacing the lazy object with the
369- concrete one. Reification imports the module in the same way as it would have
370- been if it had been imported eagerly. Notably, reification still calls
371- ``__import__ `` to resolve the import, which uses the state of the import system
372- (e.g. ``sys.path ``, ``sys.meta_path ``, ``sys.path_hooks `` and ``__import__ ``)
373- at **reification ** time, **not ** the state when the ``lazy import `` statement
374- was evaluated.
375-
376- When the module is first reified, it's removed from ``sys.lazy_modules `` (even
377- if there are still other unreified lazy references to it). When a package is
377+ When a lazy object is used, it needs to be reified. This means resolving the
378+ import at that point in the program and replacing the lazy object with the
379+ concrete one. Reification imports the module at that point in the program.
380+ Notably, reification still calls ``__import__ `` to resolve the import, which
381+ uses the state of the import system (e.g. ``sys.path ``, ``sys.meta_path ``,
382+ ``sys.path_hooks `` and ``__import__ ``) at **reification ** time, **not ** the
383+ state when the ``lazy import `` statement was evaluated.
384+
385+ When the module is reified, it's removed from ``sys.lazy_modules `` (even if
386+ there are still other unreified lazy references to it). When a package is
378387reified and submodules in the package were also previously lazily imported,
379388those submodules are *not * automatically reified but they *are * added to the
380- reified package's globals (unless the package already assigned something else
381- to the name of the submodule).
389+ reified package's globals (unless the package already assigned something
390+ else to the name of the submodule).
382391
383- If reification fails (e.g., due to an ``ImportError ``), the exception is
384- enhanced with chaining to show both where the lazy import was defined and
385- where it was first accessed (even though it propagates from the code that
386- triggered reification). This provides clear debugging information:
392+ If reification fails (e.g., due to an ``ImportError ``), the lazy object is
393+ *not * reified or replaced. Subsequent uses of the lazy object will re-try
394+ the reification. Exceptions that happen during reification are raised as
395+ normal, but the exception is enhanced with chaining to show both where the
396+ lazy import was defined and where it was accessed (even though it propagates
397+ from the code that triggered reification). This provides clear debugging
398+ information:
387399
388400.. code-block :: python
389401
@@ -469,7 +481,7 @@ Example using ``globals()``:
469481 g = globals ()
470482
471483 print (' json' in sys.modules) # False - still lazy
472- print (type (g[' json' ])) # <class 'lazy_import '>
484+ print (type (g[' json' ])) # <class 'LazyImport '>
473485
474486 # Explicitly reify using the get() method
475487 resolved = g[' json' ].get()
@@ -704,7 +716,7 @@ These changes are limited to bindings explicitly made lazy:
704716
705717* **Error timing. ** Exceptions that would have occurred during an eager import
706718 (for example ``ImportError `` or ``AttributeError `` for a missing member) now
707- occur at the first *use * of the lazy name.
719+ occur at the *use * of the lazy name.
708720
709721 .. code-block :: python
710722
@@ -714,7 +726,7 @@ These changes are limited to bindings explicitly made lazy:
714726 # With lazy import - error deferred
715727 lazy import broken_module
716728 print (" Import succeeded" )
717- broken_module.foo() # ImportError raised here on first use
729+ broken_module.foo() # ImportError raised here on use
718730
719731 * **Side-effect timing. ** Import-time side effects in lazily imported modules
720732 occur at first use of the binding, not at module import time.
@@ -727,16 +739,17 @@ These changes are limited to bindings explicitly made lazy:
727739 when it is first used.
728740* **Proxy visibility. ** Before first use, the bound name refers to a lazy
729741 proxy. Indirect introspection that touches the value may observe a proxy
730- lazy object representation. After first use, the name is rebound to the real
731- object and becomes indistinguishable from an eager import.
742+ lazy object representation. After first use (provied the module was
743+ imported succesfully), the name is rebound to the real object and becomes
744+ indistinguishable from an eager import.
732745
733746Thread-safety and reification
734747-----------------------------
735748
736- First use of a lazy binding follows the existing import-lock discipline.
737- Exactly one thread performs the import and **atomically rebinds ** the
738- importing module's global to the resolved object. Concurrent readers
739- thereafter observe the real object.
749+ Reification follows the existing import-lock discipline. Exactly one thread
750+ performs the import and **atomically rebinds ** the importing module's global
751+ to the resolved object. Concurrent readers thereafter observe the real
752+ object.
740753
741754Lazy imports are thread-safe and have no special considerations for
742755free-threading. A module that would normally be imported in the main thread
@@ -758,11 +771,11 @@ code that doesn't.
758771Runtime performance
759772~~~~~~~~~~~~~~~~~~~
760773
761- After reification (first use ), lazy imports have ** zero overhead **. The
762- adaptive interpreter specializes the bytecode (typically after 2-3 accesses),
763- eliminating any checks. For example, `` LOAD_GLOBAL `` becomes
764- ``LOAD_GLOBAL_MODULE ``, which directly accesses the module identically to
765- normal imports.
774+ After reification (provided the import was succesful ), lazy imports have
775+ ** zero overhead **. The adaptive interpreter specializes the bytecode
776+ (typically after 2-3 accesses), eliminating any checks. For example,
777+ ``LOAD_GLOBAL `` becomes `` LOAD_GLOBAL_MODULE ``, which directly accesses the
778+ module identically to normal imports.
766779
767780The `pyperformance suite `_ confirms the implementation is performance-neutral.
768781
@@ -1033,6 +1046,9 @@ it was first used:
10331046 1/0
10341047 ZeroDivisionError: division by zero
10351048
1049+ Exceptions during reification prevent the replacement of the lazy object,
1050+ and subsequent uses of the lazy object will retry the whole reification.
1051+
10361052How do lazy imports affect modules with import-time side effects?
10371053-----------------------------------------------------------------
10381054
@@ -1118,8 +1134,8 @@ What's the performance overhead of lazy imports?
11181134
11191135The overhead is minimal:
11201136
1121- - Zero overhead after first use thanks to the adaptive interpreter optimizing
1122- the slow path away.
1137+ - Zero overhead after first use (provided the import doesn't fail) thanks to
1138+ the adaptive interpreter optimizing the slow path away.
11231139- Small one-time cost to create the proxy object.
11241140- Reification (first use) has the same cost as a regular import.
11251141- No ongoing performance penalty.
@@ -1159,7 +1175,7 @@ error. If lazy imports are globally enabled, star imports will still be eager.
11591175How do lazy imports interact with import hooks and custom loaders?
11601176------------------------------------------------------------------
11611177
1162- Import hooks and loaders work normally. When a lazy object is first used,
1178+ Import hooks and loaders work normally. When a lazy object is used,
11631179the standard import protocol runs, including any custom hooks or loaders that
11641180were in place at reification time.
11651181
@@ -1191,7 +1207,7 @@ reifies all lazy imports in that module first. This design ensures:
11911207 lazy import json
11921208
11931209 g = globals ()
1194- print (type (g[' json' ])) # <class 'lazy_import '> - your problem
1210+ print (type (g[' json' ])) # <class 'LazyImport '> - your problem
11951211
11961212 # From external code:
11971213 import sys
@@ -1390,11 +1406,11 @@ The best practice is still to avoid circular imports in your code design.
13901406Will lazy imports affect the performance of my hot paths?
13911407---------------------------------------------------------
13921408
1393- After first use, lazy imports have **zero overhead ** thanks to the adaptive
1394- interpreter. The interpreter specializes the bytecode (e.g., `` LOAD_GLOBAL ``
1395- becomes ``LOAD_GLOBAL_MODULE ``) which eliminates the lazy check on subsequent
1396- accesses. This means once a lazy import is reified, accessing it is just as
1397- fast as a normal import.
1409+ After first use (provided the import succeed) , lazy imports have **zero
1410+ overhead ** thanks to the adaptive interpreter. The interpreter specializes
1411+ the bytecode (e.g., `` LOAD_GLOBAL `` becomes ``LOAD_GLOBAL_MODULE ``) which
1412+ eliminates the lazy check on subsequent accesses. This means once a lazy
1413+ import is reified, accessing it is just as fast as a normal import.
13981414
13991415.. code-block :: python
14001416
0 commit comments