Почему я не могу передать декорированную функцию в scipy.integrate.ode?

Когда я передаю декорированную функцию в 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()

Что-то, вероятно, полагается на проверку подписи, чтобы определить, какие аргументы передавать. Попробуйте functools.wraps.

user2357112 16.02.2023 01:32

@ user2357112 Та же ошибка, если я правильно использовал functools. См. редактировать, чтобы опубликовать

carpanaut 16.02.2023 01:36

Чего вы, вероятно, хотите добиться, так это эффекта func = lambda t,x: func_proto(t,x,**kwargs) Такого же эффекта можно добиться, используя ключевое слово args в интеграторе. Вы должны использовать ключевые слова в своем примере, например, для фактора роста.

Lutz Lehmann 16.02.2023 13:01
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
Тонкая настройка GPT-3 с помощью Anaconda
Тонкая настройка GPT-3 с помощью Anaconda
Зарегистрируйте аккаунт Open ai, а затем получите ключ API ниже.
1
3
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

То, как вы строите декоратор, в частности внутреннюю функцию, похоже, искажает сигнатуру функции 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()

Но чего ты здесь добился? Здесь нет лишних аргументов, декоратор фактически заменяет функцию собой.

Lutz Lehmann 16.02.2023 20:33

Я максимально упростил, но по-прежнему показывал проблему. В моем реальном приложении оболочка изменяет вектор y на пути к dydt и обратно.

carpanaut 17.02.2023 03:58

Другие вопросы по теме