Skip to content

Commit 0985e2a

Browse files
committed
Doc updates
1 parent 2f7d223 commit 0985e2a

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

Doc/reference/lexical_analysis.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ Some names are only reserved under specific contexts. These are known as
457457

458458
- ``match``, ``case``, and ``_``, when used in the :keyword:`match` statement.
459459
- ``type``, when used in the :keyword:`type` statement.
460+
- ``lazy``, when used before an :keyword:`import` statement.
460461

461462
These syntactically act as keywords in their specific contexts,
462463
but this distinction is done at the parser level, not when tokenizing.
@@ -468,6 +469,9 @@ identifier names.
468469
.. versionchanged:: 3.12
469470
``type`` is now a soft keyword.
470471

472+
.. versionchanged:: next
473+
``lazy`` is now a soft keyword.
474+
471475
.. index::
472476
single: _, identifiers
473477
single: __, identifiers

Doc/reference/simple_stmts.rst

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -748,14 +748,15 @@ The :keyword:`!import` statement
748748
pair: name; binding
749749
pair: keyword; from
750750
pair: keyword; as
751+
pair: keyword; lazy
751752
pair: exception; ImportError
752753
single: , (comma); import statement
753754

754755
.. productionlist:: python-grammar
755-
import_stmt: "import" `module` ["as" `identifier`] ("," `module` ["as" `identifier`])*
756-
: | "from" `relative_module` "import" `identifier` ["as" `identifier`]
756+
import_stmt: ["lazy"] "import" `module` ["as" `identifier`] ("," `module` ["as" `identifier`])*
757+
: | ["lazy"] "from" `relative_module` "import" `identifier` ["as" `identifier`]
757758
: ("," `identifier` ["as" `identifier`])*
758-
: | "from" `relative_module` "import" "(" `identifier` ["as" `identifier`]
759+
: | ["lazy"] "from" `relative_module` "import" "(" `identifier` ["as" `identifier`]
759760
: ("," `identifier` ["as" `identifier`])* [","] ")"
760761
: | "from" `relative_module` "import" "*"
761762
module: (`identifier` ".")* `identifier`
@@ -870,6 +871,57 @@ determine dynamically the modules to be loaded.
870871

871872
.. audit-event:: import module,filename,sys.path,sys.meta_path,sys.path_hooks import
872873

874+
875+
.. _lazy-imports:
876+
877+
Lazy imports
878+
------------
879+
880+
.. index::
881+
pair: lazy; import
882+
single: lazy import
883+
884+
When an import statement is preceded by the :keyword:`lazy<lazy import>` keyword,
885+
the import becomes *lazy*: the module is not loaded immediately at the import
886+
statement. Instead, a lazy proxy object is created and bound to the name. The
887+
actual module is loaded on first use of that name.
888+
889+
.. keyword:: lazy import
890+
891+
The ``lazy`` keyword marks an import as lazy. It is a :ref:`soft keyword
892+
<soft-keywords>` that only has special meaning when it appears immediately
893+
before an :keyword:`import` or :keyword:`from` statement.
894+
895+
Lazy imports are only permitted at module scope. Using ``lazy`` inside a
896+
function, class body, or :keyword:`try`/:keyword:`except`/:keyword:`finally`
897+
block raises a :exc:`SyntaxError`. Star imports cannot be lazy (``lazy from
898+
module import *`` is a syntax error), and :ref:`future statements <future>`
899+
cannot be lazy.
900+
901+
When using ``lazy from ... import``, each imported name is bound to a lazy
902+
proxy object. The first access to any of these names triggers loading of the
903+
entire module and resolves only that specific name to its actual value. Other
904+
names remain as lazy proxies until they are accessed.
905+
906+
Example::
907+
908+
lazy import json
909+
910+
print('json' in sys.modules) # False - module not loaded yet
911+
912+
# First use triggers loading
913+
result = json.dumps({"hello": "world"})
914+
915+
print('json' in sys.modules) # True - now loaded
916+
917+
If an error occurs during module loading (such as :exc:`ImportError` or
918+
:exc:`SyntaxError`), it is raised at the point where the lazy import is first
919+
used, not at the import statement itself.
920+
921+
See :pep:`810` for the full specification of lazy imports.
922+
923+
.. versionadded:: next
924+
873925
.. _future:
874926

875927
Future statements

Doc/whatsnew/3.15.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,17 @@ runtime.
139139

140140
For more selective control, :func:`sys.set_lazy_imports_filter` accepts a callable
141141
that determines whether a specific module should be loaded lazily. The filter
142-
receives the fully-qualified module name and returns a boolean. This allows
143-
patterns like making only your own application's modules lazy while keeping
144-
third-party dependencies eager:
142+
receives three arguments: the importing module's name (or ``None``), the imported
143+
module's name, and the fromlist (or ``None`` for regular imports). It should
144+
return ``True`` to allow the import to be lazy, or ``False`` to force eager loading.
145+
This allows patterns like making only your own application's modules lazy while
146+
keeping third-party dependencies eager:
145147

146148
.. code-block:: python
147149
148150
import sys
149151
150-
sys.set_lazy_imports_filter(lambda name: name.startswith("myapp."))
152+
sys.set_lazy_imports_filter(lambda importing, imported, fromlist: imported.startswith("myapp."))
151153
sys.set_lazy_imports("all")
152154
153155
import myapp.slow_module # lazy (matches filter)

0 commit comments

Comments
 (0)