Skip to content

Commit 9d413e3

Browse files
authored
Merge branch 'main' into pep791-edits
2 parents 00f4f06 + cec9cb6 commit 9d413e3

File tree

3 files changed

+75
-58
lines changed

3 files changed

+75
-58
lines changed

peps/pep-0489.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ Python-Version: 3.5
1212
Post-History: 23-Aug-2013, 20-Feb-2015, 16-Apr-2015, 07-May-2015, 18-May-2015
1313
Resolution: https://mail.python.org/pipermail/python-dev/2015-May/140108.html
1414

15-
.. canonical-doc:: :ref:`python:initializing-modules`.
16-
For Python 3.14+, see :ref:`py3.14:extension-modules`
17-
and :ref:`py3.14:pymoduledef`
15+
.. canonical-doc:: :ref:`py3.13:initializing-modules`.
16+
For Python 3.14+, see :ref:`python:extension-modules`
17+
and :ref:`python:pymoduledef`
1818

1919
.. highlight:: c
2020

peps/pep-0745.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ Abstract
1414
This document describes the development and release schedule for
1515
Python 3.14.
1616

17-
Release Manager and Crew
17+
Release manager and crew
1818
========================
1919

20-
- 3.14 Release Manager: Hugo van Kemenade
20+
- 3.14 release manager: Hugo van Kemenade
2121
- Windows installers: Steve Dower
2222
- Mac installers: Ned Deily
2323
- Documentation: Julien Palard
2424

2525

26-
Release Schedule
26+
Release schedule
2727
================
2828

2929
3.14.0 schedule
@@ -51,11 +51,10 @@ Actual:
5151
- 3.14.0 candidate 1: Tuesday, 2025-07-22
5252
- 3.14.0 candidate 2: Thursday, 2025-08-14
5353
- 3.14.0 candidate 3: Thursday, 2025-09-18
54+
- 3.14.0 final: Tuesday, 2025-10-07
5455

5556
Expected:
5657

57-
- 3.14.0 final: Tuesday, 2025-10-07
58-
5958
Subsequent bugfix releases every two months.
6059

6160

peps/pep-0810.rst

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -335,19 +335,29 @@ An import remains lazy only if the filter function returns ``True``.
335335

336336
If 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+
338347
Lazy import mechanism
339348
---------------------
340349

341350
When 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
344353
fully-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

348357
The implementation of ``from ... import`` (the ``IMPORT_FROM`` bytecode
349358
implementation) 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

352362
The end result of this process is that lazy imports (regardless of how they
353363
are 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
356366
the ``sys.lazy_modules`` set. Under normal operation lazy objects should only
357367
end up stored in global variables, and the common ways to access those
358368
variables (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

361371
It is still possible to expose lazy objects through other means, like
362372
debuggers. This is not considered a problem.
363373

364374
Reification
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
378387
reified and submodules in the package were also previously lazily imported,
379388
those 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
@@ -428,8 +440,9 @@ referenced the module. It **only** resolves the lazy object being accessed.
428440

429441
Accessing a lazy object (from a global variable or a module attribute) reifies
430442
the object. Accessing a module's ``__dict__`` reifies **all** lazy objects in
431-
that module. Operations that indirectly access ``__dict__`` (such as
432-
:func:`dir`) also trigger this behavior.
443+
that module. Calling ``dir()`` at the global scope will not reify the globals
444+
and calling ``dir(mod)`` will be special cased in ``mod.__dir__`` avoid
445+
reification as well.
433446

434447
Example using ``__dict__`` from external code:
435448

@@ -469,7 +482,7 @@ Example using ``globals()``:
469482
g = globals()
470483
471484
print('json' in sys.modules) # False - still lazy
472-
print(type(g['json'])) # <class 'lazy_import'>
485+
print(type(g['json'])) # <class 'LazyImport'>
473486
474487
# Explicitly reify using the get() method
475488
resolved = g['json'].get()
@@ -484,6 +497,9 @@ Reference Implementation
484497
A reference implementation is available at:
485498
https://github.com/LazyImportsCabal/cpython/tree/lazy
486499

500+
A demo is available (not necessarily synced with the latest PEP) for
501+
evaluation purposes at: https://lazy-import-demo.pages.dev/
502+
487503
Bytecode and adaptive specialization
488504
-------------------------------------
489505

@@ -704,7 +720,7 @@ These changes are limited to bindings explicitly made lazy:
704720

705721
* **Error timing.** Exceptions that would have occurred during an eager import
706722
(for example ``ImportError`` or ``AttributeError`` for a missing member) now
707-
occur at the first *use* of the lazy name.
723+
occur at the *use* of the lazy name.
708724

709725
.. code-block:: python
710726
@@ -714,7 +730,7 @@ These changes are limited to bindings explicitly made lazy:
714730
# With lazy import - error deferred
715731
lazy import broken_module
716732
print("Import succeeded")
717-
broken_module.foo() # ImportError raised here on first use
733+
broken_module.foo() # ImportError raised here on use
718734
719735
* **Side-effect timing.** Import-time side effects in lazily imported modules
720736
occur at first use of the binding, not at module import time.
@@ -727,16 +743,17 @@ These changes are limited to bindings explicitly made lazy:
727743
when it is first used.
728744
* **Proxy visibility.** Before first use, the bound name refers to a lazy
729745
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.
746+
lazy object representation. After first use (provied the module was
747+
imported succesfully), the name is rebound to the real object and becomes
748+
indistinguishable from an eager import.
732749

733750
Thread-safety and reification
734751
-----------------------------
735752

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.
753+
Reification follows the existing import-lock discipline. Exactly one thread
754+
performs the import and **atomically rebinds** the importing module's global
755+
to the resolved object. Concurrent readers thereafter observe the real
756+
object.
740757

741758
Lazy imports are thread-safe and have no special considerations for
742759
free-threading. A module that would normally be imported in the main thread
@@ -758,11 +775,11 @@ code that doesn't.
758775
Runtime performance
759776
~~~~~~~~~~~~~~~~~~~
760777

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.
778+
After reification (provided the import was succesful), lazy imports have
779+
**zero overhead**. The adaptive interpreter specializes the bytecode
780+
(typically after 2-3 accesses), eliminating any checks. For example,
781+
``LOAD_GLOBAL`` becomes ``LOAD_GLOBAL_MODULE``, which directly accesses the
782+
module identically to normal imports.
766783

767784
The `pyperformance suite`_ confirms the implementation is performance-neutral.
768785

@@ -1033,6 +1050,9 @@ it was first used:
10331050
1/0
10341051
ZeroDivisionError: division by zero
10351052
1053+
Exceptions during reification prevent the replacement of the lazy object,
1054+
and subsequent uses of the lazy object will retry the whole reification.
1055+
10361056
How do lazy imports affect modules with import-time side effects?
10371057
-----------------------------------------------------------------
10381058

@@ -1118,8 +1138,8 @@ What's the performance overhead of lazy imports?
11181138

11191139
The overhead is minimal:
11201140

1121-
- Zero overhead after first use thanks to the adaptive interpreter optimizing
1122-
the slow path away.
1141+
- Zero overhead after first use (provided the import doesn't fail) thanks to
1142+
the adaptive interpreter optimizing the slow path away.
11231143
- Small one-time cost to create the proxy object.
11241144
- Reification (first use) has the same cost as a regular import.
11251145
- No ongoing performance penalty.
@@ -1159,7 +1179,7 @@ error. If lazy imports are globally enabled, star imports will still be eager.
11591179
How do lazy imports interact with import hooks and custom loaders?
11601180
------------------------------------------------------------------
11611181

1162-
Import hooks and loaders work normally. When a lazy object is first used,
1182+
Import hooks and loaders work normally. When a lazy object is used,
11631183
the standard import protocol runs, including any custom hooks or loaders that
11641184
were in place at reification time.
11651185

@@ -1191,7 +1211,7 @@ reifies all lazy imports in that module first. This design ensures:
11911211
lazy import json
11921212
11931213
g = globals()
1194-
print(type(g['json'])) # <class 'lazy_import'> - your problem
1214+
print(type(g['json'])) # <class 'LazyImport'> - your problem
11951215
11961216
# From external code:
11971217
import sys
@@ -1313,9 +1333,8 @@ How do lazy imports interact with ``dir()``, ``getattr()``, and module introspec
13131333
-------------------------------------------------------------------------------------
13141334

13151335
Accessing lazy imports through normal attribute access or ``getattr()``
1316-
will trigger reification. Calling ``dir()`` on a module will reify all lazy
1317-
imports in that module to ensure the directory listing is complete. This is
1318-
similar to accessing ``mod.__dict__``.
1336+
will trigger reification of the accessed attribute. Calling ``dir()`` on a
1337+
module will be special cased in ``mod.__dir__`` to avoid reification.
13191338

13201339
.. code-block:: python
13211340
@@ -1327,7 +1346,6 @@ similar to accessing ``mod.__dict__``.
13271346
# Any of these trigger reification:
13281347
dumps_func = json.dumps
13291348
dumps_func = getattr(json, 'dumps')
1330-
dir(json)
13311349
# Now json is in sys.modules
13321350
13331351
Do lazy imports work with circular imports?
@@ -1390,11 +1408,11 @@ The best practice is still to avoid circular imports in your code design.
13901408
Will lazy imports affect the performance of my hot paths?
13911409
---------------------------------------------------------
13921410

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.
1411+
After first use (provided the import succeed), lazy imports have **zero
1412+
overhead** thanks to the adaptive interpreter. The interpreter specializes
1413+
the bytecode (e.g., ``LOAD_GLOBAL`` becomes ``LOAD_GLOBAL_MODULE``) which
1414+
eliminates the lazy check on subsequent accesses. This means once a lazy
1415+
import is reified, accessing it is just as fast as a normal import.
13981416

13991417
.. code-block:: python
14001418

0 commit comments

Comments
 (0)