我开始通过编写ODE解算器来学习Python。我想透明地处理一个或多个变量输入函数。这是我的欧拉方法的一步代码:
def euler(h, t, y, f):
return (y + h*f for y,f in zip(y,f(t,y)))
现在我定义了两个函数,f1
和f2
,如下所示:
def f1(t,y):
return -2*t*y
def f2(t,y):
x, y = y #is rebinding usually ok, or confusing?
return (x - t*y, y + x/t)
当我测试它们时,那就是(显然)发生的事情
>>> list(euler(0.01, 1, (1,2), f2))
[0.99, 2.03]
>>> list(euler(0.01, 1, 1, f1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in euler
TypeError: zip argument #1 must support iteration
如果给定的函数适用于一个或多个变量,我希望求解器能够透明地处理,但是没有找到一个很酷的方法来完成它。我找到的方法是
import operator as op
def euler(h, t, y, f):
if op.isNumberType(y):
return (y + h*f(t,y),)
return (y + h*f for y,f in zip(y,f(t,y)))
但是现在我传递了一个浮点并返回了一个迭代,所以list(euler(...))
可以取代。但是,我无法打电话,例如,f(t,euler(...))
。
有没有办法将单例序列作为基本类型处理,或者将基元作为单例序列处理而无需无休止的检查?通过“无休止的检查”,我的意思是,只需检查几个地方,而不是我的代码。或者我应该把它搞砸并让f(t,y)
期望一个序列而不是一个数字?
感谢您的帮助,我们也欢迎您提供有关编码的提示!
答案 0 :(得分:1)
在您的euler函数中,您可以通过封装在列表中并再次尝试来捕获TypeError并进行恢复。
答案 1 :(得分:1)
一种可能的解决方案是以下列方式编写您的euler功能
def euler(h, t, y, f):
if isinstance(y,collections.Iterable):
return (y + h*f for y,f in zip(y,f(t,y)))
else:
return (y+h*f(t,y),)
另一种解决方案是将您的一维函数编写为
def f1(t,y):
return (-2*t*y[0],)
然后按以下方式调用euler
list(euler(0.01, 1, (1,), f1))
答案 2 :(得分:1)
仅使f(t,y)使用序列非常容易:
def euler(h, t, y, f):
return (y + h*v for y,v in zip(y,f(t,y)))
def f1(t,status):
x, = status
return -2*t*x,
def f2(t,status):
x, y = status
return x - t*y, y + x/t
print list(euler(0.01, 1, (1,2), f2))
print list(euler(0.01, 1, (1,), f1))