Last active
August 29, 2019 13:31
-
-
Save numberoverzero/958cd4d85708965ab05dca494ede1808 to your computer and use it in GitHub Desktop.
Python deferred instantiation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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