Operator overloading madness in python (equation builder)
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))
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
Recent Comments