PEP 810 – Explicit Lazy Imports Authors Pablo Galindo, Germán Méndez Bravo, Thomas Wouters, Dino Viehland, Brittany Reynoso, Noah Kim, Tim Stumbaugh Status Draft (Standards Track) Created: 02-Oct-2025 Python Version: 3.15 --- Abstract PEP 810 introduces explicit lazy imports in Python, where imported modules are not loaded immediately at the import statement but deferred until first use. This feature reduces startup time, memory consumption, and overhead, especially for CLI tools, test suites, and large applications. Lazy imports are enabled explicitly, keeping full backward compatibility. --- Motivation Imports are typically done at module level and executed eagerly, causing potentially unnecessary module loading. This leads to high startup latency, e.g., CLI tools loading many unused subcommands. Developers manually defer imports using inline imports inside functions but that obfuscates dependencies and is error-prone. Existing tools like importlib.util.LazyLoader or third-party modules offer partial solutions but with overhead or complexity. Lazy imports syntax is proposed to be: Local: applies only to marked imports without cascading. Explicit: marked with a new lazy keyword. Controlled: only imports marked by authors are lazy. Granular: incremental adoption possible by marking individual imports. Global flags are also proposed to enable/disable or filter lazy imports for experimentation or testing. Benefits CLI startup times reduced by 50-70%. Eliminates runtime overhead of type-checking-only imports. Large apps can save 30-40% memory by deferring unused subsystems. --- Rationale Explicit lazy keyword ensures clarity and reduces surprises. Lazy imports use proxy objects in the module namespace rather than dict hooks for simplicity and performance. A global lazymodules list allows compatibility by marking modules lazy even on older Python versions. Adoption is guaranteed to be incremental and opt-in only. Global lazy imports flag supports broad enabling combined with filters for fine control. --- Specification Grammar A new soft keyword lazy is introduced valid before import statements: Only allowed at module-level; disallowed inside functions, classes, try/with blocks, or star imports. Semantics Lazy import marks the binding as a proxy; module is loaded only upon first use. Module-level lazymodules list can mark imports as lazy automatically. A global lazy imports flag enables lazy imports broadly but obeys filters and syntax restrictions. A lazy import proxy is replaced with the actual module/object on first access. If an import error happens, it's raised with chained traceback showing the original lazy import definition and usage site. Lazy Import Mechanism Uses a new lazyimport function (similar signature to import) to create lazy module objects. Lazy module objects do not appear in sys.modules initially but are tracked in sys.lazymodules. Reification loads the module normally via import and replaces the proxy binding. Reification Happens on first use of the lazy object (attribute access, or loading from globals). Accessing a module’s dict externally reifies all lazy imports in that module. globals() returns the dict with lazy proxies intact; does not trigger reification. Lazy imports are thread-safe; a single thread performs import and atomic rebinding. --- Implementation Bytecode Changes Modified bytecodes: IMPORTNAME, IMPORTFROM, LOADGLOBAL, LOADNAME handle lazy flags. The interpreter detects lazy imports and creates proxy objects. Adaptive specialization optimizes away lazy check overhead after first use. sys Module Additions sys.setlazyimports_filter(func): sets a filter function