Когда я передаю декорированную функцию в scipy.integrate.ode, вызывается функция-оболочка, но *args пуст. Почему это происходит?
Это работает:
y0, t0 = 1, 0
def dydt(t, y):
return y*0.5
r = scipy.integrate.ode(dydt)
r.set_initial_value(y0)
r.integrate(10)
assert r.successful()
Это не:
y0, t0 = 1, 0
def dec_func(func):
def wrap_func(*args, **kwargs):
return func(*args, **kwargs)
return wrap_func
@dec_func
def dydt(t, y):
return y*0.5
r = scipy.integrate.ode(dydt)
r.set_initial_value(y0)
r.integrate(10)
assert r.successful()
Он возвращает эту ошибку: TypeError: dydt() missing 2 required positional arguments: 't' and 'y'
Когда я вставляю строку в функцию-оболочку, чтобы напечатать длину аргументов, она возвращается как 0.
Обновлено: Это тоже не работает. Тот же результат, что и в основном посте
from functools import wraps
y0, t0 = 1, 0
def dec_func(func):
@wraps(func)
def wrap_func(*args, **kwargs):
return func(*args, **kwargs)
return wrap_func
@dec_func
def dydt(t, y):
return y*0.5
r = scipy.integrate.ode(dydt)
r.set_initial_value(y0)
r.integrate(10)
assert r.successful()
@ user2357112 Та же ошибка, если я правильно использовал functools. См. редактировать, чтобы опубликовать
Чего вы, вероятно, хотите добиться, так это эффекта func = lambda t,x: func_proto(t,x,**kwargs) Такого же эффекта можно добиться, используя ключевое слово args в интеграторе. Вы должны использовать ключевые слова в своем примере, например, для фактора роста.
То, как вы строите декоратор, в частности внутреннюю функцию, похоже, искажает сигнатуру функции dydt. scipy.integrate.ode необходимо передать вызываемый f(t,y) с такой сигнатурой, что t является скаляром, y.shape == (n,) и f возвращает скаляр или список (взятый из документации scipy). Результат украшения dydt, как вы, кажется, не соответствует, хотя разница несколько теряется для меня.
Это работает следующим образом:
def dec_func(func):
def wrap_func(t, y):
return func(t, y)
return wrap_func
@dec_func
def dydt2(t, y):
return y*0.5
r = scipy.integrate.ode(dydt2)
r.set_initial_value(y0)
r.integrate(10)
assert r.successful()
Я попробовал несколько вещей, которые, как я думал, позволят вам сохранить общую внутреннюю функцию (args, kwargs), но я так и не нашел ничего, что сработало.
Дело не в том, что вы не можете передать декорированную функцию. К сожалению, есть некоторые скрытые требования к оформлению функции.
Так что это все еще открытый вопрос, что именно происходит внутри scipy. Вот обходной путь, который я использую.
y0, t0 = 1, 0
def dec_func(func):
def wrap_func(t, y, *args, **kwargs):
return func(t, y, *args, **kwargs)
return wrap_func
@dec_func
def dydt(t, y):
return y*0.5
r = scipy.integrate.ode(dydt)
r.set_initial_value(y0)
r.integrate(10)
assert r.successful()
Но чего ты здесь добился? Здесь нет лишних аргументов, декоратор фактически заменяет функцию собой.
Я максимально упростил, но по-прежнему показывал проблему. В моем реальном приложении оболочка изменяет вектор y на пути к dydt и обратно.
Что-то, вероятно, полагается на проверку подписи, чтобы определить, какие аргументы передавать. Попробуйте functools.wraps.