Skip to content

Instantly share code, notes, and snippets.

@chr5tphr
Last active October 11, 2019 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chr5tphr/3d031376ac8d95461b3673ce9885e749 to your computer and use it in GitHub Desktop.
Save chr5tphr/3d031376ac8d95461b3673ce9885e749 to your computer and use it in GitHub Desktop.
LazyProxy Python
"""LazyProxy and LazyDict for lazily evaluated objects"""
class LazyProxy:
"""Lazily apply a chain of functions on a single object"""
def __init__(self, parent=None):
"""Lazily apply a chain of functions on a single object
Parameters
----------
parent : LazyProxy or None
Previous LazyProxy in function chain, or None if root
"""
self.parent = parent
self._op = lambda x: x
def __getattr__(self, name):
"""Lazily get attribute of object"""
self._op = lambda x: getattr(x, name)
return LazyProxy(self)
def __getitem__(self, key):
"""Lazily get item of object"""
self._op = lambda x: x[key]
return LazyProxy(self)
def __call__(self, *args, **kwargs):
"""Lazily call object"""
self._op = lambda x: x(*args, **kwargs)
def op(self, func):
"""Lazily apply function on object.
Parameters
----------
func : function
Function that takes a single argument, which is object to evaluate on.
"""
self._op = func
return LazyProxy(self)
def eval(self, obj):
"""Evaluate LazyProxy function chain by supplying a root object.
Parameters
----------
obj : The object on which the function chain shall be evaluated.
"""
if self.parent is not None:
obj = self.parent.eval(obj)
return self._op(obj)
class LazyDict(dict):
"""Dict with lazily evaluated values from a fixed set of variable names"""
def __init__(self, variables=('data_out', 'data_in', 'meta')):
"""Dict with lazily evaluated values from a fixed set of variable names
Parameters
----------
variables : tuple of str
Names of fixed variables.
"""
self._variables = variables
self._variable_data = {}
def eval(self, **kwargs):
"""Evaluate all dictionary entries, and return them in a new dict
Parameters
----------
**kwargs
Exhaustive dict of values for fixed variables.
"""
self._variable_data = {}
for key in self._variables:
try:
obj = kwargs.pop(key)
except KeyError as error:
raise TypeError('Variable not supplied: \'{}\''.format(key))
self._variable_data[key] = obj
if kwargs:
raise TypeError('Unexpected variables: \'{}\''.format('\', \''.join(kwargs)))
return {key: (proxy.eval(None) if isinstance(proxy, LazyProxy) else proxy) for key, proxy in self.items()}
def proxy(self, name):
"""Get proxy object of a fixed variable.
Parameters
----------
name : str
Name of the fixed variable.
"""
if name not in self._variables:
raise TypeError('No such variable: \'{}\''.format(name))
return LazyProxy().op(lambda x: self._variable_data[name])
def __getattr__(self, name):
"""Get a proxy object when accessing instance attributes."""
if name not in self._variables:
raise AttributeError('No such variable: \'{}\''.format(name))
return self.proxy(name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment