В случае, показанном ниже, у меня есть функция под названием func1(), которая находится в func3(), где func3() вычисляет значение ОДУ с использованием метода Эйлера.
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)
Код передает func1 в func3 в качестве декоратора и записывает вывод в список по мере итерации в диапазоне от 0 до 10. Однако код внутри func3() жестко закодирован для точного ввода func1(), то есть x и y. Я хотел бы написать func3(), чтобы он был достаточно общим, чтобы вы могли передать ему любую функцию, если его первые два входа — x и y, но он должен быть способен принимать больше входных данных. Итак, предположим, что весь код, показанный выше, был идентичен, но вместо передачи func1() я передал func2() в func3() со структурой, показанной ниже.
def func2(x, y, z):
return z * y * np.log(y) / (x*z)
Как я мог написать func3(), чтобы он был достаточно универсальным, чтобы он мог принимать любую из двух функций и понимать, что у них больше аргументов для передачи в func1(), которые также должны быть переданы в func3()?






Используйте *args и **kwargs для сбора аргументов (в дополнение к x и y, предназначенным для вашего обратного вызова):
def func3(x, y, step_size, func, *args, **kwargs):
dydx = func(x, y, *args, **kwargs)
...
Однако подумайте, действительно ли func3 необходимо вызывать func себя; вместо этого сделайте это абонент.
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))
...
Вы можете использовать синтаксис аргументов переменной длины Python для ожидания любых дополнительных аргументов и передачи их дальше. Если их нет, то все равно работает: переменная со звездочкой получит в качестве значения пустой список и исчезнет при расширении осенью до 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)
Звучит как хорошая идея: если вы перепутаете аргументы, вы сразу узнаете.
Было бы лучше использовать *args и **kargs (**kwargs в определениях функций в python используется для передачи списка аргументов переменной длины с ключевыми словами. Мы используем имя kwargs с двойной звездочкой. Причина в том, что двойная star позволяет нам передавать аргументы ключевых слов и любое их количество).
Например:
def myFun (arg1, arg2, arg3):
print("arg1:", arg1)
print("arg2:", arg2)
print("arg3:", arg3)
args = ("Привет", "привет", "пока")
myFun(*аргументы)
kwargs = {"arg1" : "компьютерщик", "arg2" : "ботаник", "arg3" : "нуб" }
myFun(**kwargs)
Выход: Привет Привет до свидания Компьютерщик Зануда Новичек
Я не думаю, что вам действительно нужно принимать другие аргументы, кроме x и y, или менять func3.
Предположим, вы хотите передать z внутренней функции. И вам также нужно передать его в func3. Поскольку z не изменится во время вызова func3, вы можете просто сделать что-то вроде func3(x, y, lambda x, y : your_func (x, y , z), step) и использовать функции с любым количеством аргументов через лямбду, которая принимает x и y.
В вашем случае вызов будет выглядеть так:
x, y = func3(x_val[i], y_val[i], step_size, lambda x, y: func2(x, y, 111))
Спасибо, я использовал тот же подход, но с **kwargs, чтобы убедиться, что передаются правильные переменные.