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