Implement point arithmetic with implicit type conversion

Suppose I have a Function class whose instances are callers that take one argument. I defined point arithmetic for these classes in the literal sense. Here is a simplified version of my code (I actually have more complex behavior in __init__ and __call__ , but that doesn't matter for this question):

 class Function: ''' >>> f = Function(lambda x : x**2) >>> g = Function(lambda x : x + 4) >>> h = f/g >>> h(6) 3.6 ''' def __init__(self, func): self.func = func def __call__(self, value): return self.func(value) def __truediv__(self, other): if isinstance(other, Function): return Function(lambda x:self(x)/other(x)) else: return NotImplemented # ... 

I get stuck when I try to resolve implicit type conversions. For example, I want to write:

 >>> f = Function(lambda x : x ** 2) >>> g = f+1 >>> g(5) 26 

In other words, whenever I see a numeric object v in an arithmetic expression next to an instance of Function , I want to convert v to Function(lambda x : v) .

In addition, I want to achieve similar behavior for some of my custom types (again, when I see them in the same binary arithmetic expression with a Function object).

Although I can, of course, encode this logic using a brute-force set of regular and reflected binary arithmetic operators, each of which checks isinstance(v, numbers.Number) and isinstance(v, MyUserDefinedType) , I believe there may be a more elegant way .

Also, if other improvements are possible in my design, let me know. ( Function objects are rarely created, but are called very often, so performance is of some interest.)

EDIT:

To address the @Eric comment, I have to clarify that I have another custom Functional class:

 class Functional: ''' >>> c = [1, 2, 3] >>> f = Functional(lambda x : x + 1) >>> f(c) [2, 3, 4] >>> g = Functional(lambda x : x ** 2) >>> h = f + g >>> h(c) [3, 7, 13] ''' def __init__(self, func): self.func = func @staticmethod def from_function(self, function): return Functional(function.func) def __call__(self, container): return type(container)(self.func(c) for c in container) def __add__(self, other): if isinstance(other, Functional): return Functional(lambda x : self.func(x) + other.func(x)) else: return NotImplemented 

When I see an instance of Function and Functional in the same arithmetic expression, I want Function be implicitly converted to Functional using the Functional.from_function method.

So, the implicit type conversion hierarchy is as follows:

  • Functional
  • Function
  • anything else

And I would like to implicitly convert to the highest type in this hierarchy, visible in this arithmetic expression.

+4
source share
3 answers

Something like this for all operators will work well:

 def __truediv__(self, other): if callable(other): return Function(lambda x:self(x)/other(x)) else: return Function(lambda x:self(x)/other) 
+2
source

One option is for all the operators in the Function class to take arbitrary values ​​that will be applied to the result of the base function if they are not the functions themselves. For example, to allow f / 5 , when f is a function, just change the __truediv__ implementation that you must:

 def __truediv__(self, other): if isinstance(other, Function): return Function(lambda x:self(x)/other(x)) else: return Function(lambda x:self(x)/other) 

You can optionally perform some type checking to make sure (and raise errors earlier than later), but it works without it.

+1
source

After reading the comments and other answers, I tried this approach. I am sending it to request feedback. I like the fact that I can handle both Function and Functional one fell swoop, but I'm afraid it can be very expensive in terms of performance:

 class Function: ''' >>> f = Function(lambda x : x**2) >>> g = Function(lambda x : x + 4) >>> h = f/g >>> h(6) 3.6 >>> k = f + 1 >>> k(5) 26 >>> m = f + (lambda x : x + 1) >>> m(5) 31 ''' def __init__(self, arg): if isinstance(arg, Function): self.func = arg.func elif callable(arg): self.func = arg else: self.func = lambda x : arg def __call__(self, value): return self.func(value) def __truediv__(self, other): return self.__class__(lambda x:Function(self)(x)/Function(other)(x)) def __rtruediv__(self, other): return self.__class__(lambda x:Function(other)(x)/Function(self)(x)) def __add__(self, other): return self.__class__(lambda x:Function(self)(x)+Function(other)(x)) def __radd__(self, other): return self.__class__(lambda x:Function(other)(x)+Function(self)(x)) # ... class Functional(Function): ''' >>> c = [1, 2, 3] >>> f = Functional(lambda x : x + 1) >>> f(c) [2, 3, 4] >>> g = Functional(lambda x : x ** 2) >>> h = f + g >>> h(c) [3, 7, 13] ''' def __call__(self, container): return type(container)(self.func(c) for c in container) 
0
source

All Articles