-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-142349: Implement PEP 810 - Explicit lazy imports #142351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 67 commits
1c691ea
3b0d745
9eef03c
de281fd
41ab092
058bc6e
6d7c87a
f992ee7
6a91132
03a419a
e0878be
f9880bf
f3f5795
44a3e46
73de8d0
07a633f
20b14d9
164423b
00e7800
781eedb
9be59ec
b179da2
9078f57
f67310c
39c33df
c8c8838
7c49405
5d6026a
c0c0d80
5ff0dd2
214b254
e5e9592
aa85f9d
2799a4d
7d07ae1
c63198c
46b3b75
c5efb20
0c246bc
d9ad012
fe526b4
06b9110
ee77665
a3ddde4
cdec6a6
c3b4807
2e19765
2af21a1
34ea0a5
5166d39
a0a9184
1f6518d
90246cc
824ac88
c075f5b
59110fc
aeda7ac
8d57aca
d8f95f7
b743eb0
e6cb131
0409481
617e9d1
db151a5
ea120fc
973a4fa
266fd4d
441602a
e6633ff
2f642c8
ab07b14
76846fe
0b36549
971d395
0c019fd
8e1b20a
70e5ce7
a39cd25
f70d4df
510c200
d58b0cf
8e4f292
4cd4322
2d3681e
4cc6905
4f675fd
4c3477b
2f7d223
0985e2a
610af78
917b92e
e777866
952ac21
33dc19e
80133a5
b0adc30
470b9e4
41761e5
74b3efe
006ca9c
b5121b0
093f08b
2a514d9
74f35c4
3014816
f96a99c
c4ed3c4
5000033
a0a28c2
023f806
4b352dc
7a0ddfd
6fd8c59
a05b50d
ac80f2d
2d4bdcc
cd1878c
31b7fe9
edf9e75
4fd8fe8
5e4c90a
ca0899c
07c1738
11e5dca
9c6757c
7ef7737
1cc816b
b3060f6
909b69a
7995d56
d95fd85
3a535de
1572241
f2adb04
9bcbe0a
9715124
578dbfd
002276a
9d6c8e8
366ebd2
49712b7
c24d68f
4d1129b
931d1c1
d4196df
b437afb
9fc7da2
29bd6c4
eaf8335
b90e3ea
8639e50
37e8863
b628adf
1f67a54
2abd718
72a7111
b960d3a
9dc236e
05c1f85
4ce061e
99dae60
8fd3f20
aa2f4de
fad3ae2
0c9b6a2
80b3925
a6328d7
bf5adba
3d443ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -341,6 +341,43 @@ Importing Modules | |
|
|
||
| .. versionadded:: 3.14 | ||
|
|
||
| .. c:function:: PyImport_LazyImportsMode PyImport_GetLazyImportsMode() | ||
|
|
||
| Gets the current lazy imports mode. | ||
|
|
||
| .. versionadded:: 3.15 | ||
|
|
||
| .. c:function:: PyObject* PyImport_GetLazyImportsFilter() | ||
|
|
||
| Gets the current lazy imports filter. Returns a new reference. | ||
|
|
||
| .. versionadded:: 3.15 | ||
|
|
||
| .. c:function:: PyObject* PyImport_SetLazyImportsMode(PyImport_LazyImportsMode mode) | ||
|
|
||
| Similar to :c:func:`PyImport_ImportModuleAttr`, but names are UTF-8 encoded | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copy-paste error? This seems unrelated to the function being described. |
||
| strings instead of Python :class:`str` objects. | ||
|
|
||
| .. versionadded:: 3.15 | ||
|
|
||
| .. c:function:: PyObject* PyImport_SetLazyImportsFilter(PyObject *filter) | ||
|
|
||
| Sets the current lazy imports filter. The function should be a callable that | ||
| will receive (importing_module_name, imported_module_name, [fromlist]) when | ||
| an import can potentially be lazy. Returns True if the import should be lazy | ||
| or False otherwise. | ||
|
pablogsal marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. versionadded:: 3.15 | ||
|
|
||
| .. c:type:: PyImport_LazyImportsMode | ||
|
|
||
| Enumeration of possible lazy import modes: | ||
| - ``PyImport_LAZY_NORMAL`` | ||
| - ``PyImport_LAZY_ALL`` | ||
| - ``PyImport_LAZY_NONE`` | ||
|
pablogsal marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. versionadded:: 3.12 | ||
|
pablogsal marked this conversation as resolved.
Outdated
ZeroIntensity marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. c:function:: PyObject* PyImport_CreateModuleFromInitfunc(PyObject *spec, PyObject* (*initfunc)(void)) | ||
|
|
||
| This function is a building block that enables embedders to implement | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,6 +65,8 @@ | |
|
|
||
| .. PEP-sized items next. | ||
|
|
||
| * :pep:`810`: :ref:`Explicit lazy imports for faster startup times | ||
| <whatsnew315-pep810>` | ||
| * :pep:`799`: :ref:`A dedicated profiling package for organizing Python | ||
| profiling tools <whatsnew315-sampling-profiler>` | ||
| * :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding | ||
|
|
@@ -77,6 +79,97 @@ | |
| New features | ||
| ============ | ||
|
|
||
| .. _whatsnew315-pep810: | ||
|
|
||
| :pep:`810`: Explicit lazy imports | ||
| --------------------------------- | ||
|
|
||
| Large Python applications often suffer from slow startup times. A significant | ||
| contributor to this problem is the import system: when a module is imported, | ||
| Python must locate the file, read it from disk, compile it to bytecode, and | ||
| execute all top-level code. For applications with deep dependency trees, this | ||
| process can take seconds, even when most of the imported code is never actually | ||
| used during a particular run. | ||
|
|
||
| Developers have worked around this by moving imports inside functions, using | ||
| ``importlib`` to load modules on demand, or restructuring code to avoid | ||
|
pablogsal marked this conversation as resolved.
Outdated
|
||
| unnecessary dependencies. These approaches work but make code harder to read | ||
| and maintain, scatter import statements throughout the codebase, and require | ||
| discipline to apply consistently. | ||
|
|
||
| Python now provides a cleaner solution through explicit lazy imports using the | ||
| new ``lazy`` soft keyword. When you mark an import as lazy, Python defers the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a link to it's doc here? |
||
| actual module loading until the imported name is first used. This gives you | ||
| the organizational benefits of declaring all imports at the top of the file | ||
| while only paying the loading cost for modules you actually use. | ||
|
|
||
| The ``lazy`` keyword works with both ``import`` and ``from ... import`` statements. | ||
| When you write ``lazy import heavy_module``, Python does not immediately load the | ||
| module. Instead, it creates a lightweight proxy object. The actual module loading | ||
| happens transparently when you first access the name: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| lazy import json | ||
| lazy from datetime import datetime | ||
|
|
||
| print("Starting up...") # json and datetime not loaded yet | ||
|
|
||
| data = json.loads('{"key": "value"}') # json loads here | ||
|
DinoV marked this conversation as resolved.
Outdated
|
||
| now = datetime() # datetime loads here | ||
|
|
||
| This mechanism is particularly useful for applications that import many modules | ||
| at the top level but may only use a subset of them in any given run. The deferred | ||
| loading reduces startup latency without requiring code restructuring or conditional | ||
| imports scattered throughout the codebase. | ||
|
|
||
| When a lazy import eventually fails (for example, if the module does not exist), | ||
| Python raises the exception at the point of first use rather than at import time. | ||
| The traceback includes both the location where the name was accessed and the | ||
| original import statement, making it straightforward to diagnose the problem. | ||
|
|
||
| For cases where you want to enable lazy loading globally without modifying source | ||
| code, Python provides the :option:`-X lazy_imports <-X>` command-line option and | ||
| the :envvar:`PYTHON_LAZY_IMPORTS` environment variable. Both accept three values: | ||
| ``all`` makes all imports lazy by default, ``none`` disables lazy imports entirely | ||
| (even explicit ``lazy`` statements become eager), and ``normal`` (the default) | ||
| respects the ``lazy`` keyword in source code. The :func:`sys.set_lazy_imports` and | ||
| :func:`sys.get_lazy_imports` functions allow changing and querying this mode at | ||
| runtime. | ||
|
|
||
| For more selective control, :func:`sys.set_lazy_imports_filter` accepts a callable | ||
| that determines whether a specific module should be loaded lazily. The filter | ||
| receives the fully-qualified module name and returns a boolean. This allows | ||
| patterns like making only your own application's modules lazy while keeping | ||
| third-party dependencies eager: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| import sys | ||
|
|
||
| sys.set_lazy_imports_filter(lambda name: name.startswith("myapp.")) | ||
| sys.set_lazy_imports("all") | ||
|
|
||
| import myapp.slow_module # lazy (matches filter) | ||
| import json # eager (does not match filter) | ||
|
|
||
| For debugging and introspection, :func:`sys.get_lazy_modules` returns a set | ||
| containing the names of all modules that have been lazily imported but not yet | ||
| loaded. The proxy type itself is available as :data:`types.LazyImportType` for | ||
| code that needs to detect lazy imports programmatically. | ||
|
|
||
| There are some restrictions on where ``lazy`` can appear. Lazy imports are only | ||
| permitted at module scope; using ``lazy`` inside a function, class body, or | ||
| ``try``/``except``/``finally`` block raises a :exc:`SyntaxError`. Star imports | ||
| cannot be lazy (``lazy from module import *`` is a syntax error), and future | ||
| imports cannot be lazy either (``lazy from __future__ import ...`` raises | ||
| :exc:`SyntaxError`). | ||
|
|
||
| .. seealso:: :pep:`810` for the full specification and rationale. | ||
|
|
||
| (Contributed by Pablo Galindo Salgado and Dino Viehland.) | ||
|
pablogsal marked this conversation as resolved.
Outdated
|
||
|
|
||
|
|
||
| .. _whatsnew315-sampling-profiler: | ||
|
|
||
| :pep:`799`: High frequency statistical sampling profiler | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.