2012-04-29 31 views
1

我开始通过编写ODE求解器来学习Python。我想透明地处理一个或多个变量的输入函数。这里是我的欧拉方法的一个步骤代码:将数值类型透明地处理为单值序列(反之亦然)

def euler(h, t, y, f): 
    return (y + h*f for y,f in zip(y,f(t,y))) 

现在我定义了两个功能,f1f2这样的:

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(...))可以suceed。但是,我不能拨打电话,例如f(t,euler(...))

有没有办法将单例序列作为基元类型处理,或者将原始单元作为单例序列处理而没有无限检查?通过“无尽检查”我的意思是,必须在几个地方检查,而不是遍及我的代码。或者我应该吸吮它,并使f(t,y)期望一个序列,而不是数字?

感谢您的任何帮助,并欢迎我的编码提示!

回答

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)) 
+0

你的答案与我的不同之处如何? – Abhijit

+0

在f1之后有一个逗号。 – HYRY

+0

我喜欢@HYRY的最好,因为它证明了它们之间的相似之处。谢谢大家的答案。 –

1

在您的euler函数中,您可以捕获TypeError并通过封装在列表中并重试来恢复。

+0

'try ... catch'优先于'if'吗?在Java中(是的,我知道“Java不是Python”),最好的做法是仅在特殊情况下使用异常。 –

+0

是的,查看“鸭子打字”了解更多细节。 –

1

一种可能的解决方案是将写欧拉函数以下述方式

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],) 

,然后以下述方式

调用欧拉
list(euler(0.01, 1, (1,), f1)) 
相关问题