class Tracer(): def __init__(self): raise Exception("Use BaseTracer instead of Tracer") def _push(self, op, obj): return CompTracer(self, obj, op) def __add__(self, other): return self._push("+", other) def __sub__(self, other): return self._push("-", other) def __mul__(self, other): return self._push("*", other) def __truediv__(self, other): return self._push("/", other) def __pow__(self, other): return self._push("**", other) def __pos__(self): return self def __neg__(self): return self._push("*", -1) def __repr__(self): v = self.eval() return "" class BaseTracer(Tracer): def __init__(self, name, val=None): self.name = name self.val = val def eval(self): return self.val def __str__(self): return self.name class CompTracer(Tracer): def __init__(self, lParent, rParent, op): if not isinstance(lParent, Tracer): lParent = BaseTracer(repr(lParent), lParent) if not isinstance(rParent, Tracer): rParent = BaseTracer(repr(rParent), rParent) self.parents = [lParent, rParent] self.op = op def eval(self): l = self.parents[0].eval() r = self.parents[1].eval() if None in [l,r]: return None if self.op=="+": return l + r elif self.op=="-": return l - r elif self.op=="*": return l * r elif self.op=="/": return l / r elif self.op=="**": return l ** r def __str__(self): return "("+str(self.parents[0])+" "+self.op+" "+str(self.parents[1])+")"