Given an expensive to initialize object and 2 consumers:
class A:
def __init__():
time.sleep(42)
self.foo = 1
def func1(obj: A):
pass
def func2(obj: A):
print(A.foo)
How to create a wrapper that would delay initialization of A until any of its fields are accessed?
proxy = wrapper(A)
func1(proxy) # executes immediately
func2(proxy) # causes object initialization and waits 42 seconds.
In other words, how to delay object initialization until any of its properties are accessed in a conventional way a.foo or at worst a.__dict__['foo'].
You could write a general purpose decorator for this. Assuming you add a function called
__lazyinit__to your class, this decorator will ensure it is called before each of the decorated method that require the full initialization of the object.Examples:
Note that this isn't much different from adding a call to
self.__lazyinit__()at the beginning of every function but it does place that concern/aspect outside of the function's codeIf you're only using this for properties you could place the
@propertylogic inside of your decorator to form a@lazypropertydecorator that combines the twoAlternatively ...
If you don't want to make any changes to the original class, you could write a function that dynamically creates a wrapper class for your object instance. The function would return the un-initialized object and let the
__getattr__initialize the object when a reference is made to an attribute that is not already present (i.e. because the instance is not initialized).