Home > Programming & scripting, Python > Operator overloading madness in python (equation builder)

Operator overloading madness in python (equation builder)

September 27th, 2007

I work extra helping out as a lab assistant in the newbie programming course at the university. One of the students had a question that really didn’t matter much for the assignment, but it inspired me to write this small class, to play around a bit with abusing operator overloading to generate equations.

Basically the class is used to set up a variable, and that variable can then be used freely to create functions with one variable like this

from equationbuilder import FuncVar
>>> x=FuncVar()
>>> f = 3*x**2 - 5*x + 8
>>> f(2)
10
>>> f(3)
20

The class for this is somewhat fun in my opinion as it constructs the final callable by using nested lazy lambda functions.

from operator import add, sub, mul, div

class FuncVar(object):
    def __new__(cls, *vals):
        cls.__rmul__ = cls.__mul__
        cls.__rdiv__ = cls.__div__
        cls.__radd__ = cls.__add__
        cls.__rsub__ = cls.__sub__
        return super(FuncVar, cls).__new__(cls)

    def __init__(self, callfunc=lambda x:x):
        self.callfunc = callfunc

    def __call__(self, arg):
        return self.callfunc(arg)

    def __add__(self, other):
        return self._rfunction(other, add)
    def __sub__(self, other):
        return self._rfunction(other, sub)
    def __div__(self, other):
        return self._rfunction(other, div)
    def __mul__(self, other):
        return self._rfunction(other, mul)
    def __pow__(self, other):
        return self._rfunction(other, pow)
    def __neg__(self):
        return -1*self

    def _rfunction(self, other, op):
        if isinstance(other, FuncVar):
            return FuncVar(lambda x: op(self(x), other(x)))
        return FuncVar(lambda x: op(self(x), other))

Download script

No real point to this blog post other than to show up a few programming tricks that some people might now know about. The __new__ constructor in python for an example works wonders to set __rmul__ and so on to the same method as __mul__.
__rmul__ and the other __rXXX_ methods is called when the class is being multiplied (or whatever) by an object “from the left” such as

3 * my_instance

and the left object throws an NotImplemented exception.

The object also defaults to having a __call__ method of

lambda x:x

which means that it will simply return the value passed. As other objects apply their operations, this method will be nested inside other call-methods and when the object is finally called it will all fit together like a nice puzzle :)

buffi Programming & scripting, Python

  1. No comments yet.
  1. No trackbacks yet.