首页 > 解决方案 > “TypeError:'生成器'对象不可下标”当我尝试使用 for 循环处理二维列表时

问题描述

class test(object):
    def __init__(self, name):
        self.name = ''


testList = [(test("empty") for i in range(3)) for j in range(2)]


for m in range(3):
    for n in range(2):

        testList[m][n].name = "changed"

我正在尝试检查和更改仅包含对象的二维列表的项目。我首先构建了 2d 列表并尝试使用双 for 循环影响其中的项目,但它返回 TypeError。

Traceback (most recent call last):
  File "test.py", line 12, in <module>
    testList[m][n].name = "changed"
TypeError: 'generator' object is not subscriptable

我真的无法理解这里发生了什么,因为它看起来非常简单和可行。该脚本无法使用testList[0][0].name = "changed"(而不是testList[m][n])运行,因此我怀疑不允许循环像这样运行。但为什么?

标签: pythonfor-loopiteratorgenerator

解决方案


当你输入时(foo for i in bar),你会得到一个生成器,当你输入时,[foo for i in bar]你会得到一个列表。这两者之间的区别在于生成器在遍历时创建元素(生成),而列表将所有项目保存在内存中。这就是为什么(i for i in range(10))[2]不可能,虽然[i for i in range(10)][2]是。

当整个项目集太大而无法保存在内存中时,或者只是当您不需要同时将它们全部保存在内存中时,您应该使用生成器。例如,它们适用于在保持恒定内存使用的同时遍历文件。

现在,如果您想下标某些东西,例如foo[some_index]thenfoo需要是可下标的,而生成器不是,因为这样做会抛弃生成器存在的全部意义。虽然有人可能认为这(i for i in range(10))[2]没问题,但扩展一些生成器可能最终会陷入无限循环,例如:

from itertools import count
even = (i for i in count() if i % 2 == 0)

这是完美的有效代码。count()返回一个无限生成器。如果我们可以争论那even[1]将是2什么even[-1]?没有最后一个偶数。因此,计算将永远进行。

反正。生成器在 python 中很常见,迟早您需要将其转换为列表或元组,您可以通过将它们传递给列表或元组构造函数list(range(10))tuple(range(10)).

现在我认为我们有足够的背景来回答你的问题。您正在执行此操作testList = [(test("empty") for i in range(3)) for j in range(2)],这为我们提供了生成器列表。所以testList[m][n]减少到事情发生(test("empty") for i in range(3))[n]的地方。

如果你只是用括号替换括号,你就解决了你的问题,所以testList = [[test("empty") for i in range(3)] for j in range(2)].


推荐阅读