为什么这种线性插值不再适用于Python> 2.7?

时间:2015-04-10 09:58:24

标签: python interpolation

我在Stack Overflow上的Python中发现了这个用于线性插值的脚本。它在Python 2.7中运行良好,但在较新版本中失败。

以下是代码:

from bisect import bisect_left

class Interpolate(object):
    def __init__(self, x_list, y_list):
        if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
            raise ValueError("x_list must be in strictly ascending order!")
        x_list = self.x_list = map(float, x_list)
        y_list = self.y_list = map(float, y_list)
        intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
        self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]

    def __getitem__(self, x):
        i = bisect_left(self.x_list, x) - 1
        return self.y_list[i] + self.slopes[i] * (x - self.x_list[i])

i = Interpolate ([0,2,3], [9,5,8])
y = i[1]

这是我得到的错误:

TypeError: 'Interpolate' object does not support indexing.

改变了什么意味着代码不再起作用了?

1 个答案:

答案 0 :(得分:3)

这是对Python 3中map()函数的更改。在Python 2.x中,它将返回一个列表,但现在它返回一个迭代器。

引自What’s New in Python 3

  

map()filter()返回迭代器。如果你真的需要一个列表,那么快速解决方案就是list(map(...)),但更好的解决方法通常是使用列表解析(特别是当原始代码使用lambda时),或者重写代码以便根本不需要列表。特别棘手的是map()为函数的副作用调用;正确的转换是使用常规for循环(因为创建列表只会浪费)。

所以问题出在这两行:

x_list = self.x_list = map(float, x_list)
y_list = self.y_list = map(float, y_list)
intervals = zip(x_list, x_list[1:], y_list, y_list[1:])

当您在创建x_list(这是y_list切片)时尝试下标intervals[1:]时,它会失败,因为您无法下标迭代器。< / p>

一种解决方法是使用这些列表推导替换x_listy_list行:

x_list = self.x_list = [float(x) for x in x_list]
y_list = self.y_list = [float(y) for y in y_list]

这不仅允许下标(因此代码按预期工作),但这仍旧适用于旧版本的Python,我认为它更清楚发生了什么。