My idea is to create particular function objects that can be summed/subtracted/... together, returning a new function object that has the same properties. This example code, hopefully, demonstrates the idea:
from FuncObj import Func
# create some functions
quad = Func(lambda x: x**2)
cube = Func(lambda x: x**3)
# now combine functions as you like
plus = quad + cube
minus = quad - cube
other = quad * quad / cube
# and these can be called
plus(1) + minus(32) * other(5)
I have written the following code, which is hopefully commented and documented enough to explain what i want to achieve.
import operator
class GenericFunction(object):
""" Base class providing arithmetic special methods.
Use derived class which must implement the
__call__ method.
"""
# this way of defining special methods works well
def __add__(self, operand):
""" This is an example of a special method i want to implement. """
obj = GenericFunction()
# this is a trick from Alex Martelli at
# http://stackoverflow.com/questions/1705928/problem-with-making-object-callable-in-python
# to allow per-instance __call__ methods
obj.__class__ = type(obj.__class__.__name__, (obj.__class__,), {})
obj.__class__.__call__ = lambda s, ti: self(ti) + operand(ti)
return obj
# on the other hand this factory function seems buggy
def _method_factory(operation, name):
""" Method factory.
Parameters
----------
op : callable
an arithmetic operator from the operator module
name : str
the name of the special method that will be created
Returns
-------
method : callable
the __***__ special method
"""
def method(s, operand):
obj = GenericFunction()
obj.__class__ = type(obj.__class__.__name__, (obj.__class__,), {})
obj.__class__.__call__ = lambda s, ti: operation(s(ti), operand(ti))
return obj
return method
__sub__ = _method_factory(operator.__sub__, '__sub__')
__mul__ = _method_factory(operator.__mul__, '__mul__')
__truediv__ = _method_factory(operator.__truediv__, '__div__')
class Func(GenericFunction):
""" A customizable callable object.
Parameters
----------
func : callable
"""
def __init__(self, func):
self.func = func
def __call__(self, *args):
return self.func(*args)
if __name__ == '__main__':
# create some functions
quad = Func(lambda x: x**2)
cube = Func(lambda x: x**3)
# now combine functions
poly_plus = quad + cube
poly_minus = quad - cube
# this is the expected behaviour, and it works well
# since the __add__ method is defined correctly.
assert quad(1) + cube(1) == poly_plus(1)
# this, and the others with * and / result in a "maximum recursion depth exceeded"
assert quad(1) - cube(1) == poly_minus(1)
I think I'm missing something important but I can't see it.
EDIT
After Dietrich answer i forgot to mention a corner case. Suppose i want to subclass GenericInput and i need to customize the call method__, without passing a callable to the constructor. I have to examples, (actually this is the code for which i originally posted this question).
class NoiseInput(GenericInput):
def __init__(self, sigma, a, b, t):
""" A band-pass noisy input. """
self._noise = lfilter(b, a, np.random.normal(0, 1, len(t)))
self._noise *= sigma/self._noise.std()
self._spline = InterpolatedUnivariateSpline(t, self._noise, k=2)
def __call__(self, ti):
""" Compute value of the input at a given time. """
return self._spline(ti)
class SineInput(GenericInput):
def __init__(self, A, fc):
self.A = A
self.fc = fc
def __call__(self, ti):
return self.A*np.sin(2*np.pi*ti*self.fc)
In this case there is some more work to do.
There's a lot of code here which doesn't need to exist, and it's more complicated than it needs to be.
For example, the
__class__
attribute is one of the so-called "magic" attributes. Magic attributes are special and only need to be used in special cases, like when you are using metaprogramming. There is no need to create a class by code here.Another example is the
Func
class in your code, which doesn't actually do anything. You can safely replace it with:So you have the opposite problem: you are not "missing" anything, you have way too much.
Note that this is not the traditional way of accomplishing such a problem. Traditionally, one avoids lambdas and uses an expression tree here. The advantage of using an expression tree is that the resulting expressions can be manipulated algebraically. For example, you can solve them, compute exact derivatives, or print them out as equations.
I'm assuming that you'd want
f(x ** 2) + f(x ** 3)
to return a functionx**2 + x**3
? You could try this:which works for me and is much simpler than what you have.
EDIT:
You could probably not even bother with the
self._func
calls in the arithmetic methods and just callself
directly.