Just for reference a minimal version of this idea (which only works for the restricted cases where LazyLoader works) looks like this:
import importlib.util
import sys
import threading
from contextlib import contextmanager
_thread_local = threading.local()
_original_import = __import__
def _lazy_import_wrapper(name, globals=None, locals=None, fromlist=(), level=0):
    lazy_modules = getattr(_thread_local, 'lazy_modules', None)
    if lazy_modules is None or level != 0 or fromlist or name not in lazy_modules or name in sys.modules:
        return _original_import(name, globals, locals, fromlist, level)
    try:
        spec = importlib.util.find_spec(name)
        if spec is None or spec.loader is None:
            return _original_import(name, globals, locals, fromlist, level)
        spec.loader = importlib.util.LazyLoader(spec.loader)
        module = importlib.util.module_from_spec(spec)
        sys.modules[name] = module
        spec.loader.exec_module(module)
        return module
    except Exception:
        return _original_import(name, globals, locals, fromlist, level)
if isinstance(__builtins__, dict):
    __builtins__['__import__'] = _lazy_import_wrapper
else:
    __builtins__.__import__ = _lazy_import_wrapper
@contextmanager
def lazy_importer(lazy_modules):
    if sys.version_info >= (3, 15):
        yield
        return
    prev = getattr(_thread_local, 'lazy_modules', None)
    _thread_local.lazy_modules = lazy_modules
    try:
        yield
    finally:
        _thread_local.lazy_modules = prev
Then you can use it like this:
from lazy_import_backport import lazy_importer
__lazy_modules__ = {"this", "collections"}
with lazy_importer(__lazy_modules__):
    import json                           # This is eager because is not in __lazy_modules__
    import this                           # This is lazy (prints nothing even if normally would)
    from collections import namedtuple    # This is eager because the from ... import ...
In both <3.15 and under this PEP it will make this lazy (via different mechanisms).
For this idea you can use something like:
import sys
import importlib.util
def lazy_import(name):
    if sys.version_info >= (3, 15):
        return __lazy_import__(name)
    if name in sys.modules:
        return sys.modules[name]
    spec = importlib.util.find_spec(name)
    spec.loader = importlib.util.LazyLoader(spec.loader)
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    return module
Then in both this PEP and <3.15:
>>> import lazy_import
>>> this = lazy_import.lazy_import("this")
>>> this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
<module 'this' from '/home/pablogsal/github/lazy/Lib/this.py'>
            