I want to create a class that lazily initializes objects in the background when they are first used, but that behaves exactly like the initialized objects. It should be thread-safe. For example:
In[1]: l = LazyInitializer(list, (1, 2, 3, 4, 5))
In[2]: l.__len__()
5
My current implementation is this:
class LazyInitializer:
def __init__(self, initializer, *args, **kwargs):
self.__initializer = initializer
self.__args = args
self.__kwargs = kwargs
self.__obj = None
self.__lock = Lock()
@property
def _obj(self):
with self.__lock:
if self.__obj is None:
self.__obj = self.__initializer(*self.__args, **self.__kwargs)
return self.__obj
def __getattr__(self, item):
return getattr(self._obj, item)
This works for regular object members (functions and properties alike), but it does not for magic methods, e.g.,
In[2]: l.__len__() # works
5
In[3]: len(l) # doesn't work
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-e75269d816bd> in <module>
----> 1 len(l)
TypeError: object of type 'LazyInitializer' has no len()
An ad-hoc solution could be to explicitly implement all possible magic methods on LazyInitializer. However, isn't there any better way?