I have implemented classes for lazily evaluating configurations that are dumped to JSON. No problem there, just extend the encoder to actively evaluate the classes using a specific protocol (fixed method/property).
class DeferredCall(object):
"""Call that is evaluated lazyly"""
def __init__(self, func, *func_args, **func_kwargs):
self.func = func
self.func_args = func_args
self.func_kwargs = func_kwargs
def resolve(self): # called by JSON encoder
return self.func(*self.func_args, **self.func_kwargs)
a = DeferredCall(lambda: 1)
a # gives <[module].DeferredCall at 0x1e99410>
a.resolve() # gives 1
Now, with great power comes users that want more power. Namely, doing operations with the classes directly instead of the values they stand for. According to the python data model, this should be as simple as implementing the magic methods, such as __add__
, __len__
etc.
Adding
def __add__(self, other):
return self.resolve() + other
or
def __add__(self, other):
return self.resolve().__add__(other)
will correctly give me a + 3 == 4
.
Implementing all magic methods a bit too much, though. So I tried using __getattr__
def __getattr__(self, item):
return getattr(self.resolve(), item)
which works for a.__mul__(3) == 3
but blow up for a * 3 == 3
with TypeError: unsupported operand type(s) for *: 'DeferredCall' and 'int'
.
So is there any other way to forward operators to the wrapped values? Ideally without venturing to programmatically writing code or the hassle of __getattribute__
.