Skip to content

Instantly share code, notes, and snippets.

@Tuanm
Created July 1, 2024 18:52
Show Gist options
  • Save Tuanm/bec6296e234fe922b68eeab6385c78a6 to your computer and use it in GitHub Desktop.
Save Tuanm/bec6296e234fe922b68eeab6385c78a6 to your computer and use it in GitHub Desktop.
Create Python Instance Lazily
import dataclasses
import threading
from typing import Any, Callable, Optional, Type, TypeVar, Union
V = TypeVar("V")
def lazy(init: Union[Type[V], Callable[..., V]], *args, **kwargs) -> V:
"""
Returns a lazy instance for a specific type.
Parameters:
- init (class/function): type or function to create the instance.
"""
if init is None or not callable(init):
raise TypeError("Type must not be None or uncallable")
@dataclasses.dataclass
class _Holder:
"""Closure instance for holding actual object."""
initialized: bool
lock: threading.Lock
obj: Optional[V]
"""Actual object."""
_holder = _Holder(False, threading.Lock(), None)
def _init_obj():
"""Actually initializes holding object."""
if not _holder.initialized:
with _holder.lock:
if not _holder.initialized:
_holder.obj = init(*args, **kwargs)
_holder.initialized = True
class _Object:
def __getattribute__(self, name: str) -> Any:
_init_obj()
return getattr(_holder.obj, name)
def __str__(self):
_init_obj()
return str(_holder.obj)
return _Object() # type: ignore
import dataclasses
import time
from .lib import lazy
@dataclasses.dataclass
class Object:
value: str
def create_heavy_object():
time.sleep(20)
obj = Object("heavy")
return obj
# lazy function call
heavy_object_1 = lazy(create_heavy_object)
print(heavy_object_1)
# lazy type initialization
heavy_object_2 = lazy(Object)
print(heavy_object_2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment