Lazy Loader
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.
Warnings
- gotcha Lazily importing subpackages using `lazy.load('package.subpackage')` is discouraged. This pattern causes the parent package (`package`) to be imported immediately, negating most performance benefits. The intended use for subpackage lazy loading within a package is via `lazy.attach` in the `__init__.py` file.
- breaking Users 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.
- gotcha Lazy 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.
- gotcha When 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.
Install
-
pip install lazy-loader
Imports
- lazy.attach
import lazy_loader as lazy __getattr__, __dir__, _ = lazy.attach(__name__, __file__, subpackages=['my_subpackage'])
- lazy.load
import lazy_loader as lazy external_module = lazy.load('some_external_library')
Quickstart
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')