2

There are lots of interesting posts on this subject, but I seem to either not understand their answers, or aiming for something different. Here is what I am trying to do. I have two (or more) functions that I want to combine into a new function. The following snippet shows what I start with, and what I would like to end up with.

def a(x):
    0.2 * x[1] - 0.4 * x[0]

def b(x):
    0.4 * x[0] - 0.2 * x[1]

def ab(x):
    return [0.2 * x[1] - 0.4 * x[0], 0.4 * x[0] - 0.2 * x[1]]

the catch being, that I would like to create ab at run time dynamically. I have a list ml with all functions so I could do the following inside a new function

def abl(x):
    ml = [a, b]
    rl = []
    i = 0
    for f in ml:
        rl.append(f(x[i]))
        i = i + 1 

and then call abl. This code combines the individual functions and results in the expected output. However, for each call to abl rl has to be built anew, which seems wasteful.

Is there another way of combining a and b in order to create a new function ab?

martineau
  • 119,623
  • 25
  • 170
  • 301
Uliw
  • 71
  • 5
  • I didn't get it. What's the problem of `ab(x)` ? – Shayan Dec 03 '21 at 17:16
  • 1
    The code you have posted for `abl` doesn't seems complete. Please provide a complete, reproducible example. – rdas Dec 03 '21 at 17:16
  • have you tried `eval` https://docs.python.org/3/library/functions.html#eval – vinzenz Dec 03 '21 at 17:16
  • You don't need an `i`. More pythonic to do `for f, xi in zip(ml, x)` and use `xi` instead of `x[i]`. Actually you don't need this at all, since you want to pass the entire `x` to both `a()` and `b()` functions. Just do `for f in ml: rl.append(f(x))` – Pranav Hosangadi Dec 03 '21 at 17:19
  • Also, you'd create a new `rl` every time you call `ab()` anyway - creating it the way you do in `abl()` is no different from creating it the way you do in `ab()` – Pranav Hosangadi Dec 03 '21 at 17:20
  • The rather more interesting question is whether Python can automatically *inline* `a` and `b` in a function like `ab = lambda x: [a(x), b(x)]`. (The answer is no, unfortunately.) – chepner Dec 03 '21 at 17:25
  • nothing wrong with ab, but a bit tedious with hundreds of functions. – Uliw Dec 03 '21 at 17:26
  • why not `def abl(x): return [a(x), b(x)]` – furas Dec 03 '21 at 17:27

2 Answers2

7

You can dynamically return new functions via lambda expressions:

def a(x):
    return 0.2 * x[1] - 0.4 * x[0]

def b(x):
    return 0.4 * x[0] - 0.2 * x[1]

def combine(func1, func2):
    return lambda x: [func1(x), func2(x)]
    
ab = combine(a, b)
print(ab([1.3, 2.9]))

Output:

[0.05999999999999994, -0.05999999999999994]
Random Davis
  • 6,662
  • 4
  • 14
  • 24
3

You can extend @Random Davis's lambda approach to any number of functions using *args:

def a(x):
    return 0.2 * x[1] - 0.4 * x[0]

def b(x):
    return 0.4 * x[0] - 0.2 * x[1]

def c(x):
    return 0.5 * x[0]

def d(x):
    return 0.5 * x[1]

def combine(*args):
    return lambda x: [f(x) for f in args]

abcd = combine(a, b, c, d)
print(abcd([1.3, 2.9]))

gives

[0.05999999999999994, -0.05999999999999994, 0.65, 1.45]
Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70