generator'对象不可下标"错误

82 投票
2 回答
154780 浏览
提问于 2025-04-16 19:13

我在解决Project Euler第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 个回答

3

作为对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:]
113

你的 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))

撰写回答