11

我是 Python 新手。我正在编写一个脚本,它将使用 Runge-Kutta 方法对一组常微分方程进行数值积分。由于 Runge-Kutta 方法是一种有用的数学算法,因此我将它放在自己的 .py 文件 rk4.py 中。

def rk4(x,dt):
    k1=diff(x)*dt
    k2=diff(x+k1/2)*dt
    k3=diff(x+k2/2)*dt
    k4=diff(x+k3)*dt
    return x+(k1+2*k2+2*k3+k4)/6

该方法需要知道用户正在使用的方程组才能执行算法,因此它调用一个函数,该函数diff(x)将为 rk4 找到它需要工作的导数。由于方程会因使用而改变,我希望在运行特定问题的脚本中定义 diff()。在这种情况下,问题是水星的轨道,所以我写了mercury.py. (这不是它最终的样子,但为了弄清楚我在做什么,我已经简化了它。)

from rk4 import rk4
import numpy as np

def diff(x):
    return x

def mercury(u0,phi0,dphi):
    x=np.array([u0,phi0])
    dt=2
    x=rk4(x,dt)
    return x

mercury(1,1,2)

当我运行mercury.py 时,我得到一个错误:

  File "PATH/mercury.py", line 10, in mercury
    x=rk4(x,dt)
  File "PATH/rk4.py", line 2, in rk4
    k1=diff(x)*dt
NameError: global name 'diff' is not defined

我认为它diff()不是全局函数,当 rk4 运行时,它对 diff 一无所知。显然 rk4 是一小段代码,我可以把它塞进我当时正在使用的任何脚本中,但我认为 Runge-Kutta 积分器是一个基本的数学工具,就像 NumPy 中定义的数组一样,所以它使它成为一个被调用的函数是有意义的,而不是在每个使用它的脚本中定义的函数(可能很多)。但我也不能告诉 rk4.py 从特定的 .py 文件导入特定的差异,因为这破坏了我首先想要的 rk4 的通用性。

有没有办法在像mercury.py这样的脚本中全局定义差异,以便在调用rk4时,它会知道差异?

4

2 回答 2

11

接受函数作为参数:

def rk4(diff,  # accept an argument of the function to call
        x, dt)
    k1=diff(x)*dt
    k2=diff(x+k1/2)*dt
    k3=diff(x+k2/2)*dt
    k4=diff(x+k3)*dt
    return x+(k1+2*k2+2*k3+k4)/6

然后,当您调用 时rk4,只需传入要执行的函数:

from rk4 import rk4
import numpy as np

def diff(x):
    return x

def mercury(u0,phi0,dphi):
    x=np.array([u0,phi0])
    dt=2
    x=rk4(diff,  # here we send the function to rk4
          x, dt)
    return x
mercury(1,1,2)

mercury接受diff作为参数也可能是一个好主意,而不是从闭包(周围的代码)中获取它。然后,您必须像往常一样传递它 - 您mercury在最后一行的调用将显示为mercury(diff, 1, 1, 2).

函数是 Python 中的“一等公民”(几乎所有东西都是如此,包括类和模块),因为它们可以用作参数、保存在列表中、分配给命名空间中的名称等。

于 2012-10-02T14:17:28.523 回答
3

diff已经是模块中的全局变量mercury.py。但是为了在其中使用它,rk4.py您需要像这样导入它:

from mercury import diff

这就是你问题的直接答案。

However, passing the diff function to rk4 as suggested by @poorsod is much more elegant and also avoids a circular dependency between mercury.py and rk4.py, so I suggest you do it that way.

于 2012-10-02T14:22:58.233 回答