How to add functions

15,661

Solution 1

I don't think you can do this. However, using the __call__ magic method lets you define your own callable class which acts as a function and upon which you can define __add__:

>>> class FunctionalFunction(object):
...     def __init__(self, func):
...             self.func = func
...
...     def __call__(self, *args, **kwargs):
...             return self.func(*args, **kwargs)
...
...     def __add__(self, other):
...             def summed(*args, **kwargs):
...                     return self(*args, **kwargs) + other(*args, **kwargs)
...             return summed
...
...     def __mul__(self, other):
...             def composed(*args, **kwargs):
...                     return self(other(*args, **kwargs))
...             return composed
...
>>> triple = FunctionalFunction(lambda x: 3 * x)
>>> times_six = triple + triple
>>> times_six(2)
12
>>> times_nine = triple * triple
>>> times_nine(3)
27

Here + is overloaded to pointwise addition, and * to composition. Of course, you can do anything you like.


Interesting question for the Python gurus: why does the following not work (filthy hack though it is)?

>>> from types import MethodType, FunctionType
>>> f = lambda: None
>>> f.__add__ = MethodType(lambda self, other: "summed!", f, FunctionType)
>>> f.__add__(f)
'summed!'
>>> f + f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'function' and 'function'

Solution 2

I think what you mean to do is:

cubefunction = (lambda x: add(f(x), f(x)))

Solution 3

A bit late, but this kind of algebra can be done easily using lambda functions:

>>> f = lambda x: x*x
>>> g = lambda x: x*x
>>> h = lambda x: f(g(x))
>>> h(2)
16
>>> j = lambda x: f(x) + g(x)
>>> j(2)
8
>>>

(f and g do not need to be lambda functions)

You can do all sorts of interesting things with this. Let's say you want to define the function f(x) = 1 + x + x**2 + ... + x**n for a given n. You can do:

>>> n = 3
>>> f = lambda x: 1
>>> for i in range(n):
...     f = lambda x, j = i + 1, k = f: k(x) + x**j
... 
>>> f(2)
15

to understand why I made the lambda that way (lambda x, j = i + 1, k = f:) is better to read this: https://docs.python.org/3.5/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result

Long story short: the parameters in a lambda function do not have a local copy. If I had used the ifrom the loop as in lambda x, k = f: k(x) + x**(i + 1), we would have had the function f(x) = 1 + x**3 + x**3 + x**3.

Solution 4

In your code, f needs to be a class, not a function. If you have a class, you can implement an add(self, other) method that will overload the + operator.

Solution 5

Well I think I got something interesting to add functions. It's about lambda function and it could fix your problem. At least it fixed mine :

>>> def func( x ) :
>>>     return x
>>> 
>>> f = lambda x : func( x )
>>> sum_of_f = [ f for i in range( 5 ) ]
>>> F = lambda x : sum( [ i( x ) for i in sum_of_f ] ) 
>>> F( 1 )
5
>>> F( 2 )
10

and for those who are interested to pass parameters

>>> def func( x, p ) :
>>>     return x * p
>>>
>>> param = [ 0, 1, 2, 3, 4 ]
>>> 
>>> f = lambda x, p : func( x, p )
>>> sum_of_f = [ f for i in range( 5 ) ]
>>> F_bis = lambda x : sum( [ sum_of_f[i]( x, param[i] ) for i in range( 5 ) ] )
>>> F_bis( 1 )
10
>>> F_bis( 2 )
20
Share:
15,661
user318904
Author by

user318904

Updated on July 26, 2022

Comments

  • user318904
    user318904 over 1 year

    I have looked all over but it is a hard topic to search for without lots of noise. I want to do something like this:

    def f(arg):
      return arg * arg
    
    def add(self, other):
      return self * other
    
    f.__add__ = add
    
    cubefunction = f + f
    

    But I get errors on the assignment to cubefunction like:

    TypeError: unsupported operand type(s) for +: 'function' and 'function'
    

    Is there no function algebra possible in python or am I just making a dumb mistake?

    edit: much later, I was reading Python's official intro to functional programming (http://docs.python.org/howto/functional.html), and towards the bottom it references a third party package "functional" (http://oakwinter.com/code/functional/documentation/), which can compose functions, ie:

    >>> from functional import compose
    >>> def add(a, b):
    ...     return a + b
    ...
    >>> def double(a):
    ...     return 2 * a
    ...
    >>> compose(double, add)(5, 6)
    22