# Mathy

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128``` ```import functools as _functools import math as _math import operator as _operator _direct_operators = {'add': _operator.add, 'sub': _operator.sub, 'mul': _operator.mul, 'div': _operator.div, 'mod': _operator.mod, 'pow': _operator.pow, 'truediv': _operator.truediv, 'floordiv': _operator.floordiv, } _reflected_operators = {'radd': _operator.add, 'rsub': _operator.sub, 'rmul': _operator.mul, 'rdiv': _operator.div, 'rmod': _operator.mod, 'rpow': _operator.pow, 'rtruediv': _operator.truediv, 'rfloordiv': _operator.floordiv, } _unary_operators = {'neg': _operator.neg, 'pos': _operator.pos, 'abs': _operator.abs, 'invert': _operator.invert, } _repr_strings = {'add': '%s + %s', 'sub': '%s - %s', 'mul': '(%s) * %s', 'div': '%s / %s', 'mod': '%s %% %s', 'pow': '(%s) ** %s', 'truediv': '%s / %s', 'floordiv': '%s // %s', 'neg': '-%s', 'pos': '+%s', 'invert': '~%s', } def _generate_direct(op_func): def generated(self, other): return Expression(op_func, self, other) return generated def _generate_reflected(op_func): def generated(self, other): return Expression(op_func, other, self) return generated def _generate_unary(op_func): def generated(self, other): return Expression(op_func, self, None) return generated class _AddOperators(type): def __new__(cls, name, bases, attrs): new_class = type.__new__(cls, name, bases, attrs) new_class.add_operators_to_class(_direct_operators, _generate_direct) new_class.add_operators_to_class(_reflected_operators, _generate_reflected) new_class.add_operators_to_class(_unary_operators, _generate_unary) return new_class def add_operators_to_class(cls, operators, generator): for op_name, op_func in operators.iteritems(): op_defined = generator(op_func) setattr(cls, '__%s__' % op_name, op_defined) class Expression(object): __metaclass__ = _AddOperators def __init__(self, function, *args): self.function = function self.args = args self.has_variable = any(getattr(arg, 'has_variable', False) for arg in args) if not self.has_variable: self.cache = self() def calculate_arg(self, arg, kwargs): return arg(**kwargs) if isinstance(arg, Expression) else arg def __call__(self, **kwargs): if hasattr(self, 'cache'): return self.cache args = (self.calculate_arg(arg, kwargs) for arg in self.args) return self.function(*args) def __repr__(self): f_name = self.function.__name__ if f_name in _repr_strings: args = tuple('(%s)' % arg if isinstance(arg, Expression) and \ not isinstance(arg, Variable) else arg for arg in self.args) return _repr_strings[f_name] % args f_module = self.function.__module__ return '%s.%s(%s)' % (f_module, f_name, ', '.join(repr(arg) for arg in self.args)) class Variable(Expression): has_variable = True def __init__(self, name): self.name = name def __call__(self, **kwargs): if self.name in kwargs: return kwargs[self.name] raise ValueError('Variable `%s` is not defined in the expression.' % self.name) def __repr__(self): return self.name mathycate = lambda function: _functools.partial(Expression, function) e = _math.e pi = _math.pi acos = mathycate(_math.acos) asin = mathycate(_math.asin) atan = mathycate(_math.atan) atan2 = mathycate(_math.atan2) ceil = mathycate(_math.ceil) cos = mathycate(_math.cos) cosh = mathycate(_math.cosh) degrees = mathycate(_math.degrees) exp = mathycate(_math.exp) fabs = mathycate(_math.fabs) floor = mathycate(_math.floor) fmod = mathycate(_math.fmod) frexp = mathycate(_math.frexp) hypot = mathycate(_math.hypot) ldexp = mathycate(_math.ldexp) log = mathycate(_math.log) log10 = mathycate(_math.log10) modf = mathycate(_math.modf) pow = mathycate(_math.pow) radians = mathycate(_math.radians) sin = mathycate(_math.sin) sinh = mathycate(_math.sinh) sqrt = mathycate(_math.sqrt) tan = mathycate(_math.tan) tanh = mathycate(_math.tanh) ```