“'生成器'对象不可订阅”错误

时间:2011-06-09 04:15:13

标签: python generator

为什么我在尝试解决Project Euler Problem 11时从代码的第5行收到此错误?

for x in matrix:
    p = 0
    for y in x:
        if p < 17:
            currentProduct = int(y) * int(x[p + 1]) * int(x[p + 2]) * int(x[p + 3])
            if currentProduct > highestProduct:
                print(currentProduct)
                highestProduct = currentProduct
        else:
                break
            p += 1
'generator' object is not subscriptable

2 个答案:

答案 0 :(得分:37)

您的x值是一个生成器对象,它是Iterator:它按顺序生成值,因为for循环或next(x)请求它们}。

您尝试访问它,就像它是一个列表或其他Sequence类型一样,它允许您按索引访问任意元素x[p + 1]

如果要按索引查找生成器输出的值,可能需要将其转换为列表:

x = list(x)

这解决了您的问题,在大多数情况下都适用。但是,这需要一次生成并保存所有值,因此如果您处理极长或无限的值列表,或者值非常大,则可能会失败。

如果您只需要生成器中的单个值,则可以使用itertools.islice(x, p)丢弃第一个p值,然后使用next(...)来获取所需的值。这样就无需在内存中保存多个项目或计算超出您正在查找的项目的值。

import itertools

result = next(itertools.islice(x, p))

答案 1 :(得分:0)

作为 Jeremy 回答的扩展,关于您的代码设计的一些想法:

看看你的算法,看起来你实际上并不需要真正随机访问生成器产生的值:在任何时候你只需要保留四个连续的值(三个,额外的优化) .这在您的代码中有点模糊,因为您混合了索引和迭代:如果索引可以工作(它没有),您的 y 可以写为 x[p + 0]

对于此类算法,您可以应用某种“滑动窗口”技术,如下面代码的精简版本所示:

import itertools, functools, operator
vs = [int(v) for v in itertools.islice(x, 3)]
for v in x:
    vs.append(int(v))
    currentProduct = functools.reduce(operator.mul, vs, 1)
    print(currentProduct)
    vs = vs[1:]