This document explains the internal workings of the Load module, focusing on package loading, memory management, and the module's architecture.
- Module Loading Flow
- Memory Management
- Module Caching
- Lazy Loading
- Performance Considerations
- Troubleshooting
When you use load.package_name, here's what happens under the hood:
-
Attribute Access
- The
__getattr__method inLoadModuleis triggered - This is the entry point for all dynamic imports
- Source:
LoadModule.__getattr__in__init__.py
- The
-
Module Resolution
- Checks if the module is already imported in
sys.modules - If not, attempts to import it using Python's import system
- Source: Dynamic import in
core.py
- Checks if the module is already imported in
-
Package Installation (if needed)
- If the module isn't found, attempts to install it
- Supports PyPI, GitHub, and local packages
- Source: Package installation logic
- Loaded modules are cached in
sys.modules - Subsequent imports return the cached module instance
- This is standard Python behavior that Load leverages
- Python's garbage collector automatically cleans up unused modules
- Modules remain in memory as long as there are references to them
- Use
delto remove references when done with large modules
To monitor memory usage:
import sys
import psutil
import os
def get_memory_usage():
process = psutil.Process(os.getpid())
return process.memory_info().rss / 1024 / 1024 # MB
print(f"Memory before: {get_memory_usage():.2f} MB")
import numpy as np
print(f"Memory after numpy: {get_memory_usage():.2f} MB")Load implements lazy loading to minimize memory usage:
-
On-Demand Loading
- Modules are only loaded when first accessed
- This is handled by
__getattr__inLoadModule - Source: Lazy loading implementation
-
Submodule Loading
- For packages like
matplotlib.pyplot, submodules are loaded on-demand - This prevents loading unnecessary components
- Source: Submodule handling
- For packages like
- First import of a module is the most expensive
- Subsequent imports are nearly instant (from cache)
- Use
import_aliases()for bulk imports:from load import import_aliases np, pd, plt = import_aliases('numpy', 'pandas', 'plt=matplotlib.pyplot')
-
Selective Importing
# Instead of import numpy as np # Use from numpy import array, mean
-
Unloading Modules
import sys if 'numpy' in sys.modules: del sys.modules['numpy']
-
Using Context Managers
from contextlib import contextmanager @contextmanager def import_temporarily(module_name): module = __import__(module_name) try: yield module finally: if module_name in sys.modules: del sys.modules[module_name] with import_temporarily('numpy') as np: # Use numpy here result = np.array([1, 2, 3]) # numpy is unloaded here
-
Module Not Found
- Check if the package is installed
- Verify the package name is correct
- Check for typos in the module name
-
Memory Leaks
- Large modules can consume significant memory
- Use
delto remove references when done - Monitor memory usage with
psutil
-
Import Errors
- Check Python version compatibility
- Verify package dependencies
- Look for naming conflicts
-
Verbose Loading
import load load.enable_auto_print() # Shows loading information
-
Module Inspection
import sys print(sys.modules.keys()) # Show all loaded modules
-
Memory Profiling
# Install memory_profiler pip install memory_profiler # Create test_script.py from memory_profiler import profile @profile def test(): import numpy as np return np.random.rand(1000, 1000) if __name__ == '__main__': test() # Run with memory profiler python -m memory_profiler test_script.py
The Load module provides a powerful and flexible way to handle Python imports with intelligent memory management. By understanding its internals, you can optimize your application's performance and resource usage.