2
\$\begingroup\$

I am writing a class for delayed operations on variables which are resolved at a later time. I am using pythons operator overloading but my class definition seems very boilerplatey.

Is there a more succinct way to define the following class?

from functools import partialmethod
import operator


class Forward:

    def resolve(self, env):
        raise NotImplementedError()

    def op(self, op, rhs):
        if not isinstance(rhs, Forward):
            raise TypeError('"{}" not of type `Forward`'.format(rhs))
        return Evaluation(op, self, rhs)

    __eq__ = partialmethod(op, operator.__eq__)
    __gt__ = partialmethod(op, operator.__gt__)
    __lt__ = partialmethod(op, operator.__lt__)
    __ge__ = partialmethod(op, operator.__ge__)
    __le__ = partialmethod(op, operator.__le__)

    __add__ = partialmethod(op, operator.__add__)
    __sub__ = partialmethod(op, operator.__sub__)
    __mul__ = partialmethod(op, operator.__mul__)
    __truediv__ = partialmethod(op, operator.__truediv__)
    __floordiv__ = partialmethod(op, operator.__floordiv__)
    __pow__ = partialmethod(op, operator.__pow__)

    __iadd__ = partialmethod(op, operator.__iadd__)
    __isub__ = partialmethod(op, operator.__isub__)
    __imul__ = partialmethod(op, operator.__imul__)
    __itruediv__ = partialmethod(op, operator.__itruediv__)
    __ifloordiv__ = partialmethod(op, operator.__ifloordiv__)
    __ipow__ = partialmethod(op, operator.__ipow__)


class Evaluation(Forward):

    def __init__(self, op, lhs, rhs):
        self.op = op
        self.lhs = lhs
        self.rhs = rhs

    def resolve(self, env):
        return self.op(self.lhs.resolve(env), self.rhs.resolve(env))


class Constant(Forward):

    def __init__(self, value):
        self.value = value

    def resolve(self, env):
        return self.value


class Variable(Forward):

    def __init__(self, name):
        self.name = name

    def resolve(self, env):
        return env[self.name]


if __name__ == "__main__":
    print((Variable('a') + Variable('b')).resolve({'a': 1, 'b': 2})

This code is part of a larger project which operates on time series data, I wanted a small way to add conditions that would evaluate whether or not to perform some other action based on the data (env) at that time, for example.

# All stages in a `pipeline` run each time a new entry is available.
# Log when simply logs the current data when `func` returns `True`.
pipeline.add(LogWhen(level=error, func=Variable('cash') < Constant(0)))

I have included enough code to demonstrate the purpose of this code but I am mainly concerned with defining the magic_methods on the Forward class. However review on any parts of the code is welcome.

\$\endgroup\$
  • \$\begingroup\$ I Didn't want to add the full code as it was just adding methods to the class that I wasn't entirely happy with, a full example with some testcases can be seen here gist.github.com/justinfay/de189fc136ebf3d11261106b6f50bce5 \$\endgroup\$ – Justin Fay Jun 18 at 13:05
  • 2
    \$\begingroup\$ I think your question could be improved by including at least a few lines of the test/example code so that people that are interested in your question see what it is about without looking at the repo. \$\endgroup\$ – AlexV Jun 18 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.