The `lazy-loader` library makes it easy to load Python subpackages and functions on demand. This utility is designed to help projects, especially in the scientific Python ecosystem, reduce startup time and memory usage by deferring module imports until the imported objects are actually accessed. It is actively maintained, currently at version 0.5, and sees regular updates to enhance functionality and fix bugs.
Install & Compatibility
Where this runs
tested against v0.5 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.925 runs
installs and imports cleanly · install 0.0s · import 0.010s · 18.6MB
glibcpy 3.10–3.925 runs
installs and imports cleanly · install 1.6s · import 0.010s · 19MB
17MB installed
● package 17MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
attach
✓ from lazy_loader import attach
✗ import lazy_loader as lazy
load
✓ from lazy_loader import load
DelayedImportErrorModule
✓ from lazy_loader import DelayedImportErrorModule
This example demonstrates how to use `lazy.attach` within a package's `__init__.py` to lazily load submodules. The `heavy_module` is only imported (and its 'imported!' message printed) when one of its attributes is first accessed, not during the initial `import mypackage` statement. This is the primary use case for `lazy-loader` to improve package import times.
import lazy_loader as lazy
import os
# This would typically be in your package's __init__.py
# For demonstration, we simulate it.
# Define a dummy 'heavy_module' that prints when imported
# In a real scenario, this would be a separate file or external library
with open('heavy_module.py', 'w') as f:
f.write("""print('heavy_module imported!')
def expensive_func():
return 'Result from expensive_func'
""")
# Create a dummy package directory and __init__.py
os.makedirs('mypackage', exist_ok=True)
with open('mypackage/__init__.py', 'w') as f:
f.write("""import lazy_loader as lazy
__getattr__, __dir__, _ = lazy.attach(
__name__, __file__,
subpackages=[
'heavy_module', # This will be lazily loaded
],
attributes={
'my_utility_func': ('some_utility_module', 'my_utility_func') # Example for external functions
}
)
# If you also wanted to lazy load an external library directly (less common in __init__.py)
# external_lib = lazy.load('sys') # Example: lazily load 'sys'
""")
print("Before importing mypackage")
import mypackage
print("After importing mypackage (heavy_module not yet loaded)")
# Accessing an attribute of mypackage.heavy_module triggers its load
result = mypackage.heavy_module.expensive_func()
print(f"Accessed heavy_module: {result}")
# Clean up dummy files
os.remove('heavy_module.py')
os.remove('mypackage/__init__.py')
os.rmdir('mypackage')
Debug
Known issues
breakingThe `subpackages` argument for `lazy.attach()` was removed in `lazy-loader` version 0.4. Attempting to use this argument will result in a `TypeError`. The previous recommendation for lazily loading subpackages using this argument is no longer valid.fixFor `lazy-loader` versions 0.4 and later, do not use the `subpackages` argument with `lazy.attach()`. Instead, `lazy.attach(__name__, __file__)` should be used for the package itself. Subpackage lazy loading should be handled by explicitly defining `__getattr__` or `__dir__` to return submodules, or by using `lazy.load` within these functions. If you require the functionality of `subpackages` for `lazy.attach`, you would need to downgrade to `lazy-loader` version `0.3.x`.
affects: 0.4 and later
breakingUsers on specific patch versions of Python 3.11 and 3.12 may encounter a known race condition due to upstream Python bugs affecting `lazy-loader`'s functionality.fixUpgrade Python to version 3.11.9 or later, or 3.12.3 or later, to avoid these known race conditions.
affects: <3.11.9, <3.12.3
gotchaLazy loading can defer import errors until runtime, making early detection of missing dependencies or typos harder during development. For debugging, `lazy-loader` can be disabled.fixSet the `EAGER_IMPORT` environment variable to `1` (e.g., `EAGER_IMPORT=1 python your_script.py`) to force eager loading of all modules managed by `lazy-loader`. This allows import errors to surface immediately upon program startup.
affects: All versions
gotchaWhen using the `require` argument in `lazy.load()` to specify version requirements (e.g., `lazy.load('numpy', require='numpy>=1.24')`), the requirement string must use the *package distribution name* (as found on PyPI), not necessarily the module import name.fixEnsure the package name in the `require` argument precisely matches the distribution name. For example, `pyyaml` is the distribution name for the `yaml` module.
affects: 0.4 and later
Audit
Dependencies
No dependency data recorded yet.