Skip to content

Commit 6ce66ec

Browse files
committed
Use subheads for Q&A
1 parent c467bff commit 6ce66ec

File tree

1 file changed

+80
-56
lines changed

1 file changed

+80
-56
lines changed

peps/pep-0810.rst

Lines changed: 80 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -829,9 +829,10 @@ avoid incompatibilities:
829829
FAQ
830830
===
831831

832-
**Q: How does this differ from the rejected PEP 690?**
832+
How does this differ from the rejected PEP 690?
833+
-----------------------------------------------
833834

834-
A: PEP 810 takes an explicit, opt-in approach instead of :pep:`690`'s implicit
835+
PEP 810 takes an explicit, opt-in approach instead of :pep:`690`'s implicit
835836
global approach. The key differences are:
836837

837838
- **Explicit syntax**: ``lazy import foo`` clearly marks which imports are
@@ -841,9 +842,10 @@ global approach. The key differences are:
841842
- **Simpler implementation**: Uses proxy objects instead of modifying core
842843
dictionary behavior.
843844

844-
**Q: What happens when lazy imports encounter errors?**
845+
What happens when lazy imports encounter errors?
846+
------------------------------------------------
845847

846-
A: Import errors (``ImportError``, ``ModuleNotFoundError``, syntax errors) are
848+
Import errors (``ImportError``, ``ModuleNotFoundError``, syntax errors) are
847849
deferred until first use of the lazy name. This is similar to moving an import
848850
into a function. The error will occur with a clear traceback pointing to the
849851
first access of the lazy object.
@@ -870,26 +872,28 @@ it was first used:
870872
1/0
871873
ZeroDivisionError: division by zero
872874
873-
**Q: How do lazy imports affect modules with import-time side effects?**
875+
How do lazy imports affect modules with import-time side effects?
876+
-----------------------------------------------------------------
874877

875-
A: Side effects are deferred until first use. This is generally desirable for
878+
Side effects are deferred until first use. This is generally desirable for
876879
performance, but may require code changes for modules that rely on import-time
877880
registration patterns. We recommend:
878881

879882
- Use explicit initialization functions instead of import-time side effects
880883
- Call initialization functions explicitly when needed
881884
- Avoid relying on import order for side effects
882885

883-
**Q: Can I use lazy imports with** ``from ... import ...`` **statements?**
886+
Can I use lazy imports with ``from ... import ...`` statements?
887+
---------------------------------------------------------------
884888

885-
A: Yes, as long as you don't use ``from ... import *``. Both ``lazy import
889+
Yes, as long as you don't use ``from ... import *``. Both ``lazy import
886890
foo`` and ``lazy from foo import bar`` are supported. The ``bar`` name will be
887891
bound to a lazy object that resolves to ``foo.bar`` on first use.
888892

889-
**Q: Does** ``lazy from module import Class`` **load the entire module or just
890-
the class?**
893+
Does ``lazy from module import Class`` load the entire module or just the class?
894+
--------------------------------------------------------------------------------
891895

892-
A: It loads the **entire module**, not just the class. This is because
896+
It loads the **entire module**, not just the class. This is because
893897
Python's import system always executes the complete module file -- there's no
894898
mechanism to execute only part of a ``.py`` file. When you first access
895899
``Class``, Python:
@@ -924,9 +928,10 @@ at the import statement.
924928
loaded. You cannot selectively load only parts of a module -- Python's import
925929
system doesn't support partial module execution.
926930

927-
**Q: What about type annotations and** ``TYPE_CHECKING`` **imports?**
931+
What about type annotations and ``TYPE_CHECKING`` imports?
932+
----------------------------------------------------------
928933

929-
A: Lazy imports eliminate the common need for ``TYPE_CHECKING`` guards. You
934+
Lazy imports eliminate the common need for ``TYPE_CHECKING`` guards. You
930935
can write:
931936

932937
.. code-block:: python
@@ -947,9 +952,10 @@ Instead of:
947952
def process(items: Sequence[str]) -> Mapping[str, int]:
948953
...
949954
950-
**Q: What's the performance overhead of lazy imports?**
955+
What's the performance overhead of lazy imports?
956+
------------------------------------------------
951957

952-
A: The overhead is minimal:
958+
The overhead is minimal:
953959

954960
- Zero overhead after first use thanks to the adaptive interpreter optimizing
955961
the slow path away.
@@ -964,50 +970,56 @@ performance neutral when lazy imports are not used.
964970
free-threading-benchmarking/blob/main/results/bm-20250922-3.15.0a0-27836e5/
965971
bm-20250922-vultr-x86_64-DinoV-lazy_imports-3.15.0a0-27836e5-vs-base.svg
966972

967-
**Q: Can I mix lazy and eager imports of the same module?**
973+
Can I mix lazy and eager imports of the same module?
974+
----------------------------------------------------
968975

969-
A: Yes. If module ``foo`` is imported both lazily and eagerly in the same
976+
Yes. If module ``foo`` is imported both lazily and eagerly in the same
970977
program, the eager import takes precedence and both bindings resolve to the
971978
same module object.
972979

973-
**Q: How do I migrate existing code to use lazy imports?**
980+
How do I migrate existing code to use lazy imports?
981+
---------------------------------------------------
974982

975-
A: Migration is incremental:
983+
Migration is incremental:
976984

977985
1. Identify slow-loading modules using profiling tools.
978986
2. Add ``lazy`` keyword to imports that aren't needed immediately.
979987
3. Test that side-effect timing changes don't break functionality.
980988
4. Use :data:`!__lazy_modules__` for compatibility with older Python versions.
981989

982-
**Q: What about star imports** (``from module import *``)?
990+
What about star imports (``from module import *``)?
991+
---------------------------------------------------
983992

984-
A: Wild card (star) imports cannot be lazy - they remain eager. This is
993+
Wild card (star) imports cannot be lazy - they remain eager. This is
985994
because the set of names being imported cannot be determined without loading
986995
the module. Using the ``lazy`` keyword with star imports will be a syntax
987996
error. If lazy imports are globally enabled, star imports will still be eager.
988997

989-
**Q: How do lazy imports interact with import hooks and custom loaders?**
998+
How do lazy imports interact with import hooks and custom loaders?
999+
------------------------------------------------------------------
9901000

991-
A: Import hooks and loaders work normally. When a lazy object is first used,
1001+
Import hooks and loaders work normally. When a lazy object is first used,
9921002
the standard import protocol runs, including any custom hooks or loaders that
9931003
were in place at reification time.
9941004

995-
**Q: What happens in multi-threaded environments?**
1005+
What happens in multi-threaded environments?
1006+
--------------------------------------------
9961007

997-
A: Lazy import reification is thread-safe. Only one thread will perform the
1008+
Lazy import reification is thread-safe. Only one thread will perform the
9981009
actual import, and the binding is atomically updated. Other threads will see
9991010
either the lazy proxy or the final resolved object.
10001011

1001-
**Q: Can I force reification of a lazy import without using it?**
1012+
Can I force reification of a lazy import without using it?
1013+
----------------------------------------------------------
10021014

1003-
A: Yes, accessing a module's ``__dict__`` will reify all lazy objects in that
1015+
Yes, accessing a module's ``__dict__`` will reify all lazy objects in that
10041016
module. Individual lazy objects can be resolved by calling their ``get()``
10051017
method.
10061018

1007-
**Q: What's the difference between** ``globals()`` **and** ``mod.__dict__``
1008-
**for lazy imports?**
1019+
What's the difference between :func:`globals` and ``mod.__dict__`` for lazy imports?
1020+
------------------------------------------------------------------------------------
10091021

1010-
A: Calling ``globals()`` returns the module's dictionary without reifying lazy
1022+
Calling ``globals()`` returns the module's dictionary without reifying lazy
10111023
imports -- you'll see lazy proxy objects when accessing them through the
10121024
returned dictionary. However, accessing ``mod.__dict__`` from external code
10131025
reifies all lazy imports in that module first. This design ensures:
@@ -1030,24 +1042,27 @@ This distinction means adding lazy imports and calling ``globals()`` is your
10301042
responsibility to manage, while external code accessing ``mod.__dict__``
10311043
always sees fully loaded modules.
10321044

1033-
**Q: Why not use** ``importlib.util.LazyLoader`` **instead?**
1045+
Why not use ``importlib.util.LazyLoader`` instead?
1046+
--------------------------------------------------
10341047

1035-
A: ``LazyLoader`` has significant limitations:
1048+
``LazyLoader`` has significant limitations:
10361049

10371050
- Requires verbose setup code for each lazy import.
10381051
- Has ongoing performance overhead on every attribute access.
10391052
- Doesn't work well with ``from ... import`` statements.
10401053
- Less clear and standard than dedicated syntax.
10411054

1042-
**Q: Will this break tools like** ``isort`` **or** ``black``?
1055+
Will this break tools like ``isort`` or ``black``?
1056+
--------------------------------------------------
10431057

1044-
A: Tools will need updates to recognize the ``lazy`` keyword, but the changes
1058+
Tools will need updates to recognize the ``lazy`` keyword, but the changes
10451059
should be minimal since the import structure remains the same. The keyword
10461060
appears at the beginning, making it easy to parse.
10471061

1048-
**Q: How do I know if a library is compatible with lazy imports?**
1062+
How do I know if a library is compatible with lazy imports?
1063+
-----------------------------------------------------------
10491064

1050-
A: Most libraries should work fine with lazy imports. Libraries that might
1065+
Most libraries should work fine with lazy imports. Libraries that might
10511066
have issues:
10521067

10531068
- Those with essential import-time side effects (registration,
@@ -1057,10 +1072,10 @@ have issues:
10571072

10581073
When in doubt, test lazy imports with your specific use cases.
10591074

1060-
**Q: What happens if I globally enable lazy imports mode and a library doesn't
1061-
work correctly?**
1075+
What happens if I globally enable lazy imports mode and a library doesn't work correctly?
1076+
-----------------------------------------------------------------------------------------
10621077

1063-
A: *Note: This is an advanced feature.* You can use the lazy imports filter to
1078+
*Note: This is an advanced feature.* You can use the lazy imports filter to
10641079
exclude specific modules that are known to have problematic side effects:
10651080

10661081
.. code-block:: python
@@ -1082,15 +1097,17 @@ forces an eager import.
10821097
Alternatively, set the global mode to ``"disabled"`` via ``-X
10831098
lazy_imports=disabled`` to turn off all lazy imports for debugging.
10841099

1085-
**Q: Can I use lazy imports inside functions?**
1100+
Can I use lazy imports inside functions?
1101+
----------------------------------------
10861102

1087-
A: No, the ``lazy`` keyword is only allowed at module level. For
1103+
No, the ``lazy`` keyword is only allowed at module level. For
10881104
function-level lazy loading, use traditional inline imports or move the import
10891105
to module level with ``lazy``.
10901106

1091-
**Q: What about forwards compatibility with older Python versions?**
1107+
What about forwards compatibility with older Python versions?
1108+
-------------------------------------------------------------
10921109

1093-
A: Use the :data:`!__lazy_modules__` global for compatibility:
1110+
Use the :data:`!__lazy_modules__` global for compatibility:
10941111

10951112
.. code-block:: python
10961113
@@ -1112,9 +1129,12 @@ maximum predictability, it's recommended to define :data:`!__lazy_modules__`
11121129
once, before any imports. But as it is checked on each import, it can be
11131130
modified between ``import`` statements.
11141131

1115-
**Q: How do explicit lazy imports interact with PEP-649/PEP-749**
1132+
How do explicit lazy imports interact with PEP 649 and PEP 749?
1133+
---------------------------------------------------------------
11161134

1117-
A: If an annotation is not stringified, it is an expression that is evaluated
1135+
Python 3.14 implemented deferred evaluation of annotations,
1136+
as specified by :pep:`649` and :pep:`749`.
1137+
If an annotation is not stringified, it is an expression that is evaluated
11181138
at a later time. It will only be resolved if the annotation is accessed. In
11191139
the example below, the ``fake_typing`` module is only loaded when the user
11201140
inspects the ``__annotations__`` dictionary. The ``fake_typing`` module would
@@ -1128,10 +1148,10 @@ also be loaded if the user uses ``annotationlib.get_annotations()`` or
11281148
pass
11291149
print(foo.__annotations__) # Triggers loading the fake_typing module
11301150
1131-
**Q: How do lazy imports interact with** :func:`dir`, :func:`getattr`, **and
1132-
module introspection?**
1151+
How do lazy imports interact with :func:`dir`, :func:`getattr`, and module introspection?
1152+
-----------------------------------------------------------------------------------------
11331153

1134-
A: Accessing lazy imports through normal attribute access or ``getattr()``
1154+
Accessing lazy imports through normal attribute access or ``getattr()``
11351155
will trigger reification. Calling ``dir()`` on a module will reify all lazy
11361156
imports in that module to ensure the directory listing is complete. This is
11371157
similar to accessing ``mod.__dict__``.
@@ -1149,9 +1169,10 @@ similar to accessing ``mod.__dict__``.
11491169
dir(json)
11501170
# Now json is in sys.modules
11511171
1152-
**Q: Do lazy imports work with circular imports?**
1172+
Do lazy imports work with circular imports?
1173+
-------------------------------------------
11531174

1154-
A: Lazy imports don't automatically solve circular import problems. If two
1175+
Lazy imports don't automatically solve circular import problems. If two
11551176
modules have a circular dependency, making the imports lazy might help **only
11561177
if** the circular reference isn't accessed during module initialization.
11571178
However, if either module accesses the other during import time, you'll still
@@ -1205,9 +1226,10 @@ which then tries to access ``module_a`` before it's fully initialized.
12051226

12061227
The best practice is still to avoid circular imports in your code design.
12071228

1208-
**Q: Will lazy imports affect the performance of my hot paths?**
1229+
Will lazy imports affect the performance of my hot paths?
1230+
---------------------------------------------------------
12091231

1210-
A: After first use, lazy imports have **zero overhead** thanks to the adaptive
1232+
After first use, lazy imports have **zero overhead** thanks to the adaptive
12111233
interpreter. The interpreter specializes the bytecode (e.g., ``LOAD_GLOBAL``
12121234
becomes ``LOAD_GLOBAL_MODULE``) which eliminates the lazy check on subsequent
12131235
accesses. This means once a lazy import is reified, accessing it is just as
@@ -1242,9 +1264,10 @@ You can observe the specialization using ``dis.dis(use_json, adaptive=True)``:
12421264
The specialized ``LOAD_GLOBAL_MODULE`` and ``LOAD_ATTR_MODULE`` instructions
12431265
are optimized fast paths with no overhead for checking lazy imports.
12441266

1245-
**Q: What about** ``sys.modules``? **When does a lazy import appear there?**
1267+
What about :data:`sys.modules`? When does a lazy import appear there?
1268+
---------------------------------------------------------------------
12461269

1247-
A: A lazily imported module does **not** appear in ``sys.modules`` until it's
1270+
A lazily imported module does **not** appear in ``sys.modules`` until it's
12481271
reified (first used). Once reified, it appears in ``sys.modules`` just like
12491272
any eager import.
12501273

@@ -1259,9 +1282,10 @@ any eager import.
12591282
12601283
print('json' in sys.modules) # True
12611284
1262-
**Q: Why you chose** ``lazy`` **as the keyword name?**
1285+
Why you chose ``lazy`` as the keyword name?
1286+
-------------------------------------------
12631287

1264-
A: Not "why"... memorize! :)
1288+
Not "why"... memorize! :)
12651289

12661290
Alternate Implementation Ideas
12671291
==============================

0 commit comments

Comments
 (0)