Lazy, Cached, Singleton Imports
Using Dunder Methods
Created: 2022-01-06
Problem: You need to make a resource available for import, but it requires some additional processing before being ready.
Examples:
- ORM Sessions/Engines
- Different modules should use the same ORM connection
- Loggers
- You want to use a logger, but with each import the logging handlers are duplicated
How We Approach with Cached Properties
This is a common pattern to cache
class MyResource:
def __init__(self):
self.cached_ = None
@property
def cached(self):
if self.cached_:
return self.cached_
self.cached_ = one_time_load()
return self.cached_
Notice we could have used a Class Attribute which would be shared across all instances of MyResource
Imports
Here's how to do something similar with a module (typing is helpful but optional)
from typing import Any
_MY_RESOURCE=None
def _load_resource():
global _MY_RESOURCE
if _MY_RESOURCE:
# We've already loaded our resource
return _MY_RESOURCE
# one time operation
_MY_RESOURCE = some_value
return _MY_RESOURCE
# This is the good part
def __getattr__(name: str) -> Any:
if name == "MY_RESOURCE":
return _load_resource()
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
And now we can simply import MY_RESOURCE
knowing we're getting _MY_RESOURCE
!
We're defining a
If you found this use of