在Python中传递参数化函数句柄

时间:2016-01-14 18:22:03

标签: python function lambda partial-application

我有一个通用函数,用于定义我计划使用scipy.integrate.odeint集成的ODE形式,例如:

def my_ode(K, tau, y, u):
  return K*u/tau - y/tau  # dydt

我的代码中有几个对象都具有my_ode中定义的格式的动态,但具有唯一参数Ktau。我希望能够在初始化对象时使用已经设置的参数将唯一句柄传递给my_ode,这样当我更新对象时,我所要做的就是soln = odeint(my_ode, t, y, u)对于某些模拟时间t

例如,如果我定义一个类:

class MyThing:
  def __init__(self, ode, y0):
    # I would rather not maintain K and tau in the objects, I just want the ODE with unique parameters here.
    self.ode = ode
    self.y = y0
    self.time = 0.0

  def update(self, t, u):
    # I want this to look something like:
    self.y = scipy.integrate.odeint(self.ode, t, self.y, u)

初始化MyThing的实例时,是否可以对Lambdas执行某些操作,以便在初始化时基本上分配参数Ktau,而不需要再次传递它们?我有点卡住了。

2 个答案:

答案 0 :(得分:3)

如果你有:

def my_ode(K, tau, y, u):
    return K*u/tau - y/tau
你可以定义类似的东西:

def make_ode_helper(k, tau): 
    return lambda (y, u): my_ode(K, tau, y, u)

并且应该能够使用以下内容初始化MyThing:

mt = new MyThing(make_ode_helper(k, tau), y0)

然后你可以用y和u参数调用这个帮助器:

someresult = ode_helper(y, u)

答案 1 :(得分:0)

使用lambda

的解决方案

在初始化对象时,看起来我可以使用lambdas生成独特的函数句柄。为了与odeint兼容,我需要定义我的函数,以便前两个参数是时间和初始状态:

def my_ode(t, y, u, K, tau):
  return K*u/tau - y/tau  # dydt

接下来,我可以使用lambdas初始化MyThing的对象,将Ktau设置为:

thing1 = MyThing(lambda t, y, u: my_ode(t, y, u, 10.0, 0.5), 0.0)

分配给thing1.ode的函数句柄现在是lambda返回的函数句柄(这可能不是正确的说法),其值为Ktau组。现在在thing1.update,我需要进行一些更改才能使其与odeint一起使用:

def update(self, t_step, t_end, u):
  t_array = np.arange(self.time, t_end, t_step)  # time values at which to evaluate ODE
  response = scipy.integrate.odeint(self.ode, self.y, t_array, (u,))
  self.y = response[-1]  # current state is the last evaluated state

让我感到震惊的一件事是,你的ODE的任何额外参数都需要作为元组传递给odeint。这看起来对我想要的效果非常好。

还有更多面向对象的方法使用scipy.integrate.ode,它允许逐步集成函数,非常适合我的模拟目的。为此,我设置对象的ODE并用以下内容更新它:

class MyThing():
  def __init__(self, ode, y0):
    self.ode = integrate.ode(ode)  # define the ODE
    self.ode.set_integrator("dopri5")  # choose an integrator
    self.ode.set_initial_value(y0)

  def update(self, u, t_step):
    """Update the ODE step-wise."""
    self.ode.set_f_params(u)  # need to pass extra parameters with this method
    self.ode.integrate(self.ode.t + t_step)  # step-wise update
    return self.ode.successful()

  def get_output(self):
    """Get output from ODE function."""
    return self.ode.y