0

In the case shown below I have a function titled func1() that resides in func3(), where func3() is solving for the value of an ODE using the Euler method.

def func1(x, y):
    return y * np.log(y) / x

def func3(x, y, step_size, func):
    dydx = func(x, y)
    new_x = x + step_size
    new_y = y _ step_size * dydx
    return new_x, new_y

step_size - 0.1
lower = 2.0
upper = 3.0
e = 2.7182828284

x_val = [2.0]
y_val = [e]
for i in range(10):
    x, y = func3(x_val[i], y_val[i], step_size, func1)
    x_val.append(x)
    y_val.append(y)

The code is passing func1 to func3 as a decorator and writing the output to a list as it iterates over the range of 0 to 10. However, the code inside func3() is hardcoded to the exact input of func1(), which is x and y. I would like to write func3() to be generic enough that you can pass any function to it as long as its first two inputs are x and y, but it should be cabaple of taking more inputs. So assume that all the code shown above was identical, but instead of passing func1(), I passed func2() to func3(), with the structure whown below.

def func2(x, y, z):
    return z * y * np.log(y) / (x*z)

How could I write func3() to be generic enough that it could take either of the two functions and understand that their are more arguments to pass to func1(), which would also have to be passed into func3()?

4 Answers 4

1

You can use Python's variable-length argument syntax to await any extra arguments, and pass them on. If there are none, it works anyway: The starred variable will receive the empty list as its value, and will disappear when expanded in the fall to func.

def func1(x, y):
    return x+y

def func2(x, y, z):
    return (x+y)*z

def caller(func, x, y, other, other2, *args):
    return func(x, y, *args)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I took the same approach but with **kwargs to ensure that the correct variables were being passed.
Sounds like a good idea: if you mix up the arguments, you will know right away.
0

Use *args and **kwargs to collect arguments (in addition to x and y intended for your callback):

def func3(x, y, step_size, func, *args, **kwargs):
    dydx = func(x, y, *args, **kwargs)
    ...

However, consider if it's really necessary for func3 to call func itself; have the caller do it instead.

def func3(x, y, step_size, dydx):
    new_x = x + step_size
    new_y = y - step_size * dydx
    return new_x, new_y

for old_x, old_y in zip(x_val, y_val):
    x, y = func3(old_x, old_y, step_size, func1(x, y))
    ...

Comments

0

It would be better to use *args and **kargs (**kwargs in function definitions in python is used to pass a keyworded, variable-length argument list. We use the name kwargs with the double star. The reason is because the double star allows us to pass through keyword arguments and any number of them).

For Example:

def myFun(arg1, arg2, arg3):

print("arg1:", arg1) 

print("arg2:", arg2) 

print("arg3:", arg3) 

args = ("Hey", "hi", "bye")

myFun(*args)

kwargs = {"arg1" : "Geek", "arg2" : "Nerd", "arg3" : "Noob" }

myFun(**kwargs)

Output: Hey hi bye Geek Nerd Noob

Comments

0

I don’t think that you really need to accept other arguments except x and y or change func3.

Let’s assume you want to pass z to inner function. And you need to pass it to func3 as well. Since z will not change during func3 call you can just do something like func3(x, y, lambda x, y : your_func (x, y , z), step) and use functions with any number of arguments through lambda which accepts x and y.

In your case call will look like:

x, y = func3(x_val[i], y_val[i], step_size, lambda x, y: func2(x, y, 111))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.