英文:
Why can't I pass a decorated function to 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'
当我在包装函数中插入一行代码来打印args
的长度时,它返回为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()
英文:
When I pass a decorated function to scipy.integrate.ode, the wrapper function gets called, but *args is empty. Why is this happening?
This works:
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()
This doesn't:
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()
It return this error: TypeError: dydt() missing 2 required positional arguments: 't' and 'y'
When I insert a line into the wrapper function to print the length of args, it comes back as 0.
EDIT:
This doesn't work either. Same result as main post
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()
答案1
得分: 0
你构建装饰器的方式,特别是内部函数,似乎扭曲了 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),但我从未找到有效的方法。
并不是说您不能传递一个经过装饰的函数。不幸的是,似乎存在一些关于如何装饰函数的隐藏要求。
英文:
The way you are constructing the decorator -- in particular the inner function -- seems to mangle the function signature of dydt
. scipy.integrate.ode
needs to be passed a callable f(t,y) with signature such that t is a scalar, y.shape == (n,)
and f
returns a scalar or list (taken from the scipy docs). The result of decorating dydt
the way you did does not seem to conform -- although the difference is somewhat lost on me.
doing it this way works:
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()
I did try a few things that I thought would allow you to keep the inner function generic (args, kwargs), but I never found anything that worked.
It's not that you can't pass a decorated function. Unfortunately there seem to be some hidden requirements as to the way the function is decorated, though.
答案2
得分: 0
所以关于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()
英文:
So it's still an open question exactly what is going on inside scipy. Here is the workaround I'm going with.
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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论