Last active
October 11, 2019 13:06
-
-
Save chr5tphr/3d031376ac8d95461b3673ce9885e749 to your computer and use it in GitHub Desktop.
LazyProxy Python
This file contains 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
"""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