# PEP 810: Explicit lazy imports

**URL:** <https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131>\
**Category:** PEPs\
**Created:** [October 3, 2025, 11:50am UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131 "2025-10-03T11:50:19Z")\
**Posts on this page:** 20\
**Page:** 7

<div class="post-metadata">

**Author:** ![dimaqq](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dimaqq/32/372_2.png) [@dimaqq](https://discuss.python.org/u/dimaqq)\
**Post date:** [October 6, 2025, 11:28am UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/123 "2025-10-06T11:28:18Z")

</div>

> [@Nineteendo](#):
>
> Would this not work?
> 
> ```python
> @app.command()
> def serve(port: int = typer.Option(None, "--port", "-p", help="Port to listen on")):
> if port is None:
> port = DEFAULT_PORT
> with socketserver.TCPServer(("", port), http.server.SimpleHTTPRequestHandler) as httpd:
> ...
> 
> ```

No, because the default value is shown in the `--help` output:

> **[CLI Arguments with Default - Typer](https://typer.tiangolo.com/tutorial/arguments/default/?h=default#an-optional-cli-argument-with-a-default)**
>
> Typer, build great CLIs. Easy to code. Based on Python type hints.

---

<div class="post-metadata">

**Author:** ![dimaqq](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dimaqq/32/372_2.png) [@dimaqq](https://discuss.python.org/u/dimaqq)\
**Post date:** [October 6, 2025, 11:31am UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/124 "2025-10-06T11:31:35Z")

</div>

> [@ofek](#):
>
> > [@dimaqq](#):
> >
> > Without the work done on a real app, I would personally consider the spec too abstract.
> 
> The work has already been done as described in the motivation section of the PEP; the countless projects will simply migrate to the built-in mechanism.

I would like to see the work that has been done.

Specific repository forks I can check out and run with the forked interpreter.

---

<div class="post-metadata">

**Author:** ![JoBe](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jobe/32/26961_2.png) [@JoBe](https://discuss.python.org/u/JoBe)\
**Post date:** [October 6, 2025, 11:44am UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/125 "2025-10-06T11:44:19Z")

</div>

Well, function Parameter defaults are always evaluated before the function is called (at definition time). That means that this wouldn’t work for **any** kind of lazy import system.

---

<div class="post-metadata">

**Author:** ![dimaqq](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dimaqq/32/372_2.png) [@dimaqq](https://discuss.python.org/u/dimaqq)\
**Post date:** [October 6, 2025, 12:14pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/127 "2025-10-06T12:14:57Z")

</div>

That was exactly me point.

Lazy imports are easy to understand… but then adapting an existing codebase to actually benefit from lazy imports often turns out to be quite an involved task.

Other ecosystems took other approaches:

- tree shaking and “compile-time” module splitting in js/webpack/tollup/esbuild
- compiled languages w/ `-ffunction-sections -fdata-sections`
- rust where feature flags remove entire subgraphs
- android/.net/ios have their own hacks for fast app startup / delayed loading

I think there’s quite a bit to learn from these.

Or work to make Python “faster” overall, e.g. spread module parsing and evaluation across hardware cores, the existing `import` syntax providing clear and deterministic granularity to do so.

---

<div class="post-metadata">

**Author:** ![JoBe](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jobe/32/26961_2.png) [@JoBe](https://discuss.python.org/u/JoBe)\
**Post date:** [October 6, 2025, 12:22pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/128 "2025-10-06T12:22:07Z")

</div>

Well, I thought about splitting tasks across cores to make Python faster before, but even as it stands, doing everything we could, Python is still interpreted, and therefore ‘slow’. There will always be limits (and new possibilities too).

If someone really wants to make, say a fast CLI, they would know when to use Python (or rather: When not to use it).

There are many ways to make code fast, and there are a billion possibilities for optimizations of Python.

This `lazy import` syntax is just the tip of an iceberg, and the basis for future work that might make imports faster. I don’t think, its possible to address everything in one PEP, but I’d love to see you ideas in a PEP once this one has been finished.

---

<div class="post-metadata">

**Author:** ![jamestwebber](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jamestwebber/32/12799_2.png) [@jamestwebber](https://discuss.python.org/u/jamestwebber)\
**Post date:** [October 6, 2025, 1:34pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/129 "2025-10-06T13:34:09Z")

</div>

Why is it not sufficient to look at the listed projects that have rolled their own implementation of lazy imports? You could peruse their history and even review the discussions of those changes as they happened. You are asking for a lot of work to be done to satisfy your curiosity.

---

<div class="post-metadata">

**Author:** ![thomas](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/thomas/32/5492_2.png) [@thomas](https://discuss.python.org/u/thomas)\
**Post date:** [October 6, 2025, 4:23pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/130 "2025-10-06T16:23:03Z")

</div>

> [@barry](#):
>
> The following questions come to mind regarding the filter function.
> 
> - Is it guaranteed to be called in a thread-safe manner? Being a process-global function (since it’s currently specified to be set/get by a `sys` function, but more on that below), are there any special considerations that are needed, either from the interpreter or from the author of the filter function? The section on [thead-safety](https://peps.python.org/pep-0810/#thread-safety-and-reification) doesn’t address this directly, but I assume at least the _intent_ is that yes, it is thread safe. That section could add an explicit guarantee.

What does “calling in a thread-safe manner” _mean_? Do you just mean “it’s guaranteed not to be called from multiple threads”, or “concurrently from multiple threads”, or “concurrently from multiple threads for the same module”? It’s not, for any of these. There’s no locking. It’s just a function that’s called as part of the import mechanism, just like many other functions. An implementation that does thread-unsafe things has to perform the relevant synchronisation itself. I’m not sure it’s ever going to matter, really. I mean, the simple case is a dict or set lookup, which is not a problem. If you need to do a lookup in a container that doesn’t do thread-safe lookups, or if you need to do complex shared state manipulations in the filter function, you’ll have to lock accordingly. None of this is specific to _this_ proposal, and I think trying to spell it out every time sets a bad precedent and a bad example.

> [@barry](#):
>
> “Why you choose lazy as the keyword name” isn’t grammatically correct. Perhaps it’s missing a “did”?

… but you’re okay with the _answer_?! 😂 (FWIW, it’s a meme Pablo likes.)

> [@barry](#):
>
> I get that `module. __dict__ ` will reify any lazy imports, but I’m somewhat concerned about the readability of seeing bare `module. __dict__ ` in code. Would it not be better to add a `.reify()` method to module objects to make that explicit? It could no-op if it’s already reified.

The mechanism isn’t being advertised as _the_ way to reify all values in a module, it’s just something that’s done to keep existing code behaving as expected. Perhaps we should have an explicit way to reify everything in a module, it hasn’t really come up yet.

> [@barry](#):
>
> ` __lazy_modules__ ` → ` __lazy_imports__ ` to more closely mirror the `lazy import` syntax and `-X` flag.

I think ` __lazy_imports__ ` is too close to ` __lazy_import__ `, and also doesn’t convey that it lists modules.

> [@oscarbenjamin](#):
>
> Is it reasonable for a user of a library to expect that the library functions under ` -X lazy_imports="disabled"`?

(Replying to this one as a stand-in about the suggestion to allow the lazy imports filter to bypass the global disable.)

I think no, the library not working should be fine. The global disable isn’t meant to be a general purpose tool with common use. It’s there for the convenience of people who want to test their own modules with lazy imports disabled. I also think it’s fine for that disable to not be an option for libraries that don’t want it to be an option, and I don’t think it’s a good idea to have a complex hierarchy of enables/disables like a game of top trumps. We _may_ end up needing this but the exact shape is unclear until we have real-world experience with this. I’ve added it to rejected ideas for now (with a slightly expanded rationale) in [PEP 810: Update rejected ideas. by Yhg1s · Pull Request #4634 · python/peps · GitHub](https://github.com/python/peps/pull/4634).

---

<div class="post-metadata">

**Author:** ![tjstum](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tjstum/32/11159_2.png) [@tjstum](https://discuss.python.org/u/tjstum)\
**Post date:** [October 6, 2025, 4:46pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/131 "2025-10-06T16:46:05Z")

</div>

> [@ncoghlan](#):
>
> It does highlight a semantic detail though: do lazy imports capture the value of ` __import__ ` at the time the statement is executed (presumably on the proxy object), or do they delay looking up ` __import__ ` until reification occurs?

There are a couple comments about this issue. It is the latter; our intent is that ` __import__ ` resolution happens when reification occurs. We don’t capture the state of the import machinery at the `lazy import` statement. The PEP says

> Reification imports the module in the same way as it would have been if it had been imported eagerly, barring intervening changes to the import system (e.g. to `sys.path`, `sys.meta_path`, `sys.path_hooks` or ` __import__ `).

Do you think it would help to clarify this in the PEP?

---

<div class="post-metadata">

**Author:** ![jamestwebber](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jamestwebber/32/12799_2.png) [@jamestwebber](https://discuss.python.org/u/jamestwebber)\
**Post date:** [October 6, 2025, 5:01pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/132 "2025-10-06T17:01:05Z")

</div>

It’s a little confusing because it’s saying “the import will be the same…except for all the ways it can be different at that point”. I’m not sure what _remains_ after the cases listed in the parenthetical statement.

It might be clearer to switch it around to “lazy modules are imported using the import system at the time of reification” and if there are any exceptions to _that_ statement list what they are.

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [October 6, 2025, 5:42pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/133 "2025-10-06T17:42:16Z")

</div>

> [@jamestwebber](#):
>
> t might be clearer to switch it around to “lazy modules are imported using the import system at the time of reification” and if there are any exceptions to _that_ statement list what they are.

I agree this is the best way to explain it.

There’s enough mutable state in the import system that I think the only two viable lazy loading options are "look up the module eagerly without executing it (the `LazyLoader` approach, which the PEP has good reason not to use), and “don’t eagerly look up _anything_, not even the value of the ` __import__ ` hook” (which is the PEP’s approach, albeit not expressed entirely clearly yet).

---

<div class="post-metadata">

**Author:** ![barry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/barry/32/42_2.png) [@barry](https://discuss.python.org/u/barry)\
**Post date:** [October 6, 2025, 6:55pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/134 "2025-10-06T18:55:01Z")

</div>

> [@thomas](#):
>
> What does “calling in a thread-safe manner” _mean_? Do you just mean “it’s guaranteed not to be called from multiple threads”, or “concurrently from multiple threads”, or “concurrently from multiple threads for the same module”? It’s not, for any of these. There’s no locking. It’s just a function that’s called as part of the import mechanism, just like many other functions.

Is it though? The import system doesn’t get invoked until reification, but the filter function has to get called at the point of the lazy import statement (i.e. `IMPORT_NAME`, `IMPORT_FROM`), to determine if the import is lazy or eager, right?

---

<div class="post-metadata">

**Author:** ![barry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/barry/32/42_2.png) [@barry](https://discuss.python.org/u/barry)\
**Post date:** [October 6, 2025, 6:56pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/135 "2025-10-06T18:56:13Z")

</div>

> [@thomas](#):
>
> … but you’re okay with the _answer_?! 😂 (FWIW, it’s a meme Pablo likes.)

Ah, that’s 🍌 🍌!

But yes!

---

<div class="post-metadata">

**Author:** ![pablogsal](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pablogsal/32/32246_2.png) [@pablogsal](https://discuss.python.org/u/pablogsal)\
**Post date:** [October 6, 2025, 7:00pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/136 "2025-10-06T19:00:37Z")

</div>

The filter function is not protected by any locking but it won’t crash if is called concurrently or something like that. If two threads execute potentially-lazy imports of the same module concurrently, the filter will be called concurrently from both threads. After the filter returns, either lazy objects are created (no synchronization needed) or we enter the standard import machinery (which has its own locking) If stronger guarantees are needed because the specific implementation handles some shared resource then it must handle its own thread-safety. For read-only operations (like checking against a frozenset), no special care is needed.

---

<div class="post-metadata">

**Author:** ![barry](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/barry/32/42_2.png) [@barry](https://discuss.python.org/u/barry)\
**Post date:** [October 6, 2025, 7:01pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/137 "2025-10-06T19:01:44Z")

</div>

That’s totally reasonable semantics. I think the PEP should add some language to clarify that.

---

<div class="post-metadata">

**Author:** ![pablogsal](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pablogsal/32/32246_2.png) [@pablogsal](https://discuss.python.org/u/pablogsal)\
**Post date:** [October 6, 2025, 7:04pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/138 "2025-10-06T19:04:33Z")

</div>

I don’t mind but I think @thomas has a point that this is kind of implied and that if we start to have to write it everywhere (not only on this PEP but other places) it may be a slippery slope. I will let you two to discuss offline 😉

---

<div class="post-metadata">

**Author:** ![cmaureir](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cmaureir/32/12363_2.png) [@cmaureir](https://discuss.python.org/u/cmaureir)\
**Post date:** [October 6, 2025, 7:14pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/139 "2025-10-06T19:14:21Z")

</div>

Some time ago, @ctismer worked on implementing the ideas from PEP 690 for the PySide module ([details here](https://bugreports.qt.io/browse/PYSIDE-2404)) which ended up showing a very nice performance for the startup time of PySide application of about 10-20%. In frameworks with tons of things are initialized at import time, I believe this would be a great addition to the language.

Having an explicit keyword to have this as an `opt-in` is IMHO the best approach for this new functionality, because I do know a few things can get a bit messy if this was enforced everywhere.

---

<div class="post-metadata">

**Author:** ![brettcannon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/brettcannon/32/34895_2.png) [@brettcannon](https://discuss.python.org/u/brettcannon)\
**Post date:** [October 6, 2025, 8:00pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/140 "2025-10-06T20:00:26Z")

</div>

> IDEs and debuggers should be prepared to display lazy proxies before first use and the real objects thereafter.

The PEP doesn’t document the proxy objects at all. So how are tools like debuggers to know they are working with a proxy object? Will the type be exposed in `types`? Will there be any other exposed data that tools like debuggers can show to the user, or will it just be in the repr? I personally only care about the former and the latter is more of a question than request.

---

<div class="post-metadata">

**Author:** ![pablogsal](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pablogsal/32/32246_2.png) [@pablogsal](https://discuss.python.org/u/pablogsal)\
**Post date:** [October 6, 2025, 8:09pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/141 "2025-10-06T20:09:23Z")

</div>

> [@brettcannon](#):
>
> Will the type be exposed in `types`?

Yes! Either in `types` or `importlib`. Any preference?

---

<div class="post-metadata">

**Author:** ![brettcannon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/brettcannon/32/34895_2.png) [@brettcannon](https://discuss.python.org/u/brettcannon)\
**Post date:** [October 6, 2025, 8:13pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/142 "2025-10-06T20:13:35Z")

</div>

> [@Don-Burns](#):
>
> Shame about the decision to exclude lazy imports from try/catch blocks.

How would you have a lazy import that was triggered away from the import statement go back and have the exception raised in the `try` block? It’s very “spooky at a distance” semantics that is already tricky enough with the lazy imports (at least the PEP has the exception trigger where the code causes the import). Toss in exceptions suddenly coming from some other line of code and not where the code is executing and it seems like asking for trouble. Plus you would have to save the whole stack at the time of lazy import for that to work and it just becomes a mess and way too complicated to tackle.

As well, for your import failure case, you would want it to find the module first and then if it exists go on to be lazy. That’s how `LazyLoader` does it already, so you can get that today if you want those semantics. Otherwise you could use [`importlib.util.find_spec()`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec) to see if the module can be found and if it isn’t then do something else.

I realize this all isn’t as convenient as magically having `lazy import` work in a `try` statement, but I’m afraid this is an instance where we can’t have everything be as simple as with eager imports.

> [@Kobzol](#):
>
> The vast majority of imports in Python are used to import functions or types, and not to trigger side-effects.

Have you done an analysis to back that statement up? For instance, I see most imports import modules, so it really depends on what codebases you’re exposed to. As for side-effects, technically every import is a side-effect since it’s an `exec()` call on the source (for the default, pure Python case).

But ignoring all of that, making eager the opt-in is a bit hostile towards beginners where reasoning about lazy imports is harder than lazy imports. In that spirit, I don’t think asking us to type 5 more characters when the perf matters is a big deal.

---

<div class="post-metadata">

**Author:** ![brettcannon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/brettcannon/32/34895_2.png) [@brettcannon](https://discuss.python.org/u/brettcannon)\
**Post date:** [October 6, 2025, 8:14pm UTC](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131/143 "2025-10-06T20:14:54Z")

</div>

> [@pablogsal](#):
>
> Yes! Either in `types` or `importlib`. Any preference?

Nope, just somewhere. I don’t think any import-specific types are in `importlib` that are this far-reaching, so probably `types` makes the most sense?

[Previous page](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131.md?page=6)

[Next page](https://discuss.python.org/t/pep-810-explicit-lazy-imports/104131.md?page=8)
