@@ -87,29 +87,31 @@ New features
8787:pep: `810 `: Explicit lazy imports
8888---------------------------------
8989
90- Large Python applications often suffer from slow startup times. A significant
91- contributor to this problem is the import system: when a module is imported,
92- Python must locate the file, read it from disk, compile it to bytecode, and
93- execute all top-level code. For applications with deep dependency trees, this
94- process can take seconds, even when most of the imported code is never actually
95- used during a particular run.
90+ Large Python applications often suffer from slow startup times. A
91+ significant contributor to this problem is the import system: when a module
92+ is imported, Python must locate the file, read it from disk, compile it to
93+ bytecode, and execute all top-level code. For applications with deep
94+ dependency trees, this process can take seconds, even when most of the
95+ imported code is never actually used during a particular run.
9696
9797Developers have worked around this by moving imports inside functions, using
9898:mod: `importlib ` to load modules on demand, or restructuring code to avoid
9999unnecessary dependencies. These approaches work but make code harder to read
100100and maintain, scatter import statements throughout the codebase, and require
101101discipline to apply consistently.
102102
103- Python now provides a cleaner solution through explicit :keyword: `lazy ` imports
104- using the new ``lazy `` soft keyword. When you mark an import as lazy, Python
105- defers the actual module loading until the imported name is first used. This
106- gives you the organizational benefits of declaring all imports at the top of
107- the file while only paying the loading cost for modules you actually use.
103+ Python now provides a cleaner solution through explicit :keyword: `lazy `
104+ imports using the new ``lazy `` soft keyword. When you mark an import as
105+ lazy, Python defers the actual module loading until the imported name is
106+ first used. This gives you the organizational benefits of declaring all
107+ imports at the top of the file while only paying the loading cost for
108+ modules you actually use.
108109
109- The ``lazy `` keyword works with both ``import `` and ``from ... import `` statements.
110- When you write ``lazy import heavy_module ``, Python does not immediately load the
111- module. Instead, it creates a lightweight proxy object. The actual module loading
112- happens transparently when you first access the name:
110+ The ``lazy `` keyword works with both ``import `` and ``from ... import ``
111+ statements. When you write ``lazy import heavy_module ``, Python does not
112+ immediately load the module. Instead, it creates a lightweight proxy object.
113+ The actual module loading happens transparently when you first access the
114+ name:
113115
114116.. code-block :: python
115117
@@ -121,54 +123,59 @@ happens transparently when you first access the name:
121123 data = json.loads(' {"key": "value"}' ) # json gets loads here
122124 now = datetime() # datetime loads here
123125
124- This mechanism is particularly useful for applications that import many modules
125- at the top level but may only use a subset of them in any given run. The deferred
126- loading reduces startup latency without requiring code restructuring or conditional
127- imports scattered throughout the codebase.
128-
129- In the case where loading a lazily imported module fails (for example, if the
130- module does not exist), Python raises the exception at the point of first use
131- rather than at import time. The associated traceback includes both the location
132- where the name was accessed and the original import statement, making it
133- straightforward to diagnose & debug the failure.
134-
135- For cases where you want to enable lazy loading globally without modifying source
136- code, Python provides the :option: `-X lazy_imports <-X> ` command-line option and
137- the :envvar: `PYTHON_LAZY_IMPORTS ` environment variable. Both accept three values:
138- ``all `` makes all imports lazy by default, ``none `` disables lazy imports entirely
139- (even explicit ``lazy `` statements become eager), and ``normal `` (the default)
140- respects the ``lazy `` keyword in source code. The :func: `sys.set_lazy_imports ` and
141- :func: `sys.get_lazy_imports ` functions allow changing and querying this mode at
142- runtime.
143-
144- For more selective control, :func: `sys.set_lazy_imports_filter ` accepts a callable
145- that determines whether a specific module should be loaded lazily. The filter
146- receives three arguments: the importing module's name (or ``None ``), the imported
147- module's name, and the fromlist (or ``None `` for regular imports). It should
148- return ``True `` to allow the import to be lazy, or ``False `` to force eager loading.
149- This allows patterns like making only your own application's modules lazy while
150- keeping third-party dependencies eager:
126+ This mechanism is particularly useful for applications that import many
127+ modules at the top level but may only use a subset of them in any given run.
128+ The deferred loading reduces startup latency without requiring code
129+ restructuring or conditional imports scattered throughout the codebase.
130+
131+ In the case where loading a lazily imported module fails (for example, if
132+ the module does not exist), Python raises the exception at the point of
133+ first use rather than at import time. The associated traceback includes both
134+ the location where the name was accessed and the original import statement,
135+ making it straightforward to diagnose & debug the failure.
136+
137+ For cases where you want to enable lazy loading globally without modifying
138+ source code, Python provides the :option: `-X lazy_imports <-X> ` command-line
139+ option and the :envvar: `PYTHON_LAZY_IMPORTS ` environment variable. Both
140+ accept three values: ``all `` makes all imports lazy by default, ``none ``
141+ disables lazy imports entirely (even explicit ``lazy `` statements become
142+ eager), and ``normal `` (the default) respects the ``lazy `` keyword in source
143+ code. The :func: `sys.set_lazy_imports ` and :func: `sys.get_lazy_imports `
144+ functions allow changing and querying this mode at runtime.
145+
146+ For more selective control, :func: `sys.set_lazy_imports_filter ` accepts a
147+ callable that determines whether a specific module should be loaded lazily.
148+ The filter receives three arguments: the importing module's name (or
149+ ``None ``), the imported module's name, and the fromlist (or ``None `` for
150+ regular imports). It should return ``True `` to allow the import to be lazy,
151+ or ``False `` to force eager loading. This allows patterns like making only
152+ your own application's modules lazy while keeping third-party dependencies
153+ eager:
151154
152155.. code-block :: python
153156
154157 import sys
155158
156- sys.set_lazy_imports_filter(lambda importing , imported , fromlist : imported.startswith(" myapp." ))
159+ def myapp_filter (importing , imported , fromlist ):
160+ return imported.startswith(" myapp." )
161+ sys.set_lazy_imports_filter(myapp_filter)
157162 sys.set_lazy_imports(" all" )
158163
159164 import myapp.slow_module # lazy (matches filter)
160165 import json # eager (does not match filter)
161166
162167 For debugging and introspection, :func: `sys.get_lazy_modules ` returns a set
163- containing the names of all modules that have been lazily imported but not yet
164- loaded. The proxy type itself is available as :data: `types.LazyImportType ` for
165- code that needs to detect lazy imports programmatically.
168+ containing the names of all modules that have been lazily imported but not
169+ yet loaded. The proxy type itself is available as
170+ :data: `types.LazyImportType ` for code that needs to detect lazy imports
171+ programmatically.
166172
167173There are some restrictions on where the ``lazy `` keyword can be used. Lazy
168- imports are only permitted at module scope; using ``lazy `` inside a function,
169- class body, or ``try ``/``except ``/``finally `` block raises a :exc: `SyntaxError `.
170- Neither star imports nor future imports can be lazy (``lazy from module import * ``
171- and ``lazy from __future__ import ... `` both raise :exc: `SyntaxError `).
174+ imports are only permitted at module scope; using ``lazy `` inside a
175+ function, class body, or ``try ``/``except ``/``finally `` block raises a
176+ :exc: `SyntaxError `. Neither star imports nor future imports can be lazy
177+ (``lazy from module import * `` and ``lazy from __future__ import ... `` both
178+ raise :exc: `SyntaxError `).
172179
173180.. seealso :: :pep:`810` for the full specification and rationale.
174181
0 commit comments