Skip to content

Instantly share code, notes, and snippets.

@numberoverzero
Last active August 29, 2019 13:31
Show Gist options
  • Save numberoverzero/958cd4d85708965ab05dca494ede1808 to your computer and use it in GitHub Desktop.
Save numberoverzero/958cd4d85708965ab05dca494ede1808 to your computer and use it in GitHub Desktop.
Python deferred instantiation
import inspect
from typing import Callable, TypeDef
T = TypeDef("T")
def defer(func: Callable[[], T]) -> T:
sig = inspect.signature(func)
base = sig.return_type
double_entry = False
class Deferred(sig):
def __init__(self):
pass
def __getattribute__(self, key):
nonlocal double_entry
assert double_entry is False
double_entry = True
obj = func()
self.__dict__ = obj.__dict__
self.__class__ = obj.__class__
return obj.__getattribute__(obj, key)
return Deferred()
# ===================
# USAGE
# ===================
class Thing:
def __init__(self):
print("Expensive init here!")
self.attr = "value"
def make_thinger() -> Thing:
return Thing()
lazy_thing = defer(make_thinger)
print("after defer call")
print(lazy_thing.attr)
# Output:
# "after defer call"
# "Expensive init here!"
# "value"
import functools
import inspect
from lazy import defer
def deferred(func):
sig = inspect.signature(func)
# Wrap the initial function
@functools.wraps(func)
def wrapper(*args, **kwargs):
# When the function is called, **then** defer the
# instantiation and return a proxy object.
def real_call() -> sig.return_type:
return func(*args, **kwargs)
return defer(real_call)
return wrapper
# ===================
# USAGE
# ===================
class Thing:
def __init__(self):
@deferred
def make_thinger(attr) -> Thing:
thing = Thing()
print("Expensive function call")
thing.attr = attr
return thing
lazy_thing = make_thinger("value")
print("after defer call")
print(lazy_thing.attr)
# Output:
# "after defer call"
# "Expensive function call"
# "value"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment