遍历列表时的Python TypeError

时间:2012-06-04 15:47:21

标签: python object int typeerror iterable

我正在教自己Python 3.2,我正在尝试制作一个匹配名单的程序。 pList是一个多维列表,第0列为字符串,第1列为整数,第2列为布尔值。但是,每当我尝试调用此函数时(只有在列表中的行数为偶数时才会运行),我得到一个TypeError。

Traceback (most recent call last):
 File "C:\Users\METC\Dropbox\assassins.py", line 150, in <module>
main()
 File "C:\Users\METC\Dropbox\assassins.py", line 11, in main
update(ops, pList)
 File "C:\Users\METC\Dropbox\assassins.py", line 125, in update
b = match(pList)
 File "C:\Users\METC\Dropbox\assassins.py", line 47, in match
q, p = 0
TypeError: 'int' object is not iterable

任何帮助都会受到赞赏,但请记住,我是语言的初学者,所以请保持温和。 :)我不介意你是否太技术了;我有计算机科学的经验。

def match(pList):
    b = []
    z = len(pList)-1
    for x in range(z):
        b.append([pList[x][0],0])
    for x in range(z):
        isValid = False
        q, p = 0
        while isValid == False:
            q = random.randint(0, z)
            print('q is ' + str(q))
            if q > z:
                isValid = False
            elif q < 0:
                isValid = False
            elif pList[q][1] == True:
                isValid = False
            else:
                isValid = True
        isMatch = False
        while isMatch == False:
            if pList[q][1] == False:
                isValid = False
                while isValid == False:
                    p = random.randint(0,z)
                    print('p is ' + str(p))
                    if p > z:
                        isValid = False
                    elif p < 0:
                        isValid = False
                    elif pList[p][2] == True:
                        isValid = False
                    else:
                        if q == p:
                            isValid = False
                        else:
                            isValid = True
                print('match valid')
                b[q][1] = pList[p][0]
                isMatch = True
    print('')
    return b

2 个答案:

答案 0 :(得分:5)

这是你的构造:

q, p = 0

它试图通过迭代来解压缩单个int。这不是有效的Python语法。我想错误可能更好。

使用:

q = p = 0

代替。

答案 1 :(得分:3)

你已经使逻辑远,远过于复杂,以至于我将不得不做几次传递以使其达到规模并告诉你什么你做错了。

首先,我们将修复实际报告的错误,正如其他人所指出的那样。同时,我们应用一个简单的原则:不要与布尔文字进行比较。你不会说&#34;如果下雨是真的,我需要一把雨伞&#34;。你说&#34;如果下雨,我需要一把伞&#34;。所以切掉额外的东西。 if isValidif isValid == True 更多更清晰,因为它突出显示isValid应该是什么意思。我还要取出调试跟踪(print语句,这些语句显然只是检查代码是否做正确的事情; 首先简化代码 ,然后有更少的检查)。

def match(pList):
    b = []
    z = len(pList)-1
    for x in range(z):
        b.append([pList[x][0],0])
    for x in range(z):
        isValid = False
        q = p = 0
        while not isValid:
            q = random.randint(0, z)
            if q > z:
                isValid = False
            elif q < 0:
                isValid = False
            elif pList[q][1]:
                isValid = False
            else:
                isValid = True
        isMatch = False
        while not isMatch:
            if not pList[q][1]:
                isValid = False
                while not isValid:
                    p = random.randint(0,z)
                    if p > z:
                        isValid = False
                    elif p < 0:
                        isValid = False
                    elif pList[p][2]:
                        isValid = False
                    else:
                        if q == p:
                            isValid = False
                        else:
                            isValid = True
                b[q][1] = pList[p][0]
                isMatch = True
    return b

接下来,我们将简化条件逻辑。首先,从random.randint(0, z) 返回的结果无论如何都不能 < 0> z。这是函数最重要的部分。因此编写代码来处理这些情况毫无意义,事实上这样做是错误的。编写代码来处理某些事情意味着它可能实际发生。这对于阅读代码的人来说是一种分心,也是一种谎言。它在重要的事物之间留出了额外的空间(对random.randint的调用和对pList值的检查)。

我们还将简化if / else对,简单地相应地设置另一个布尔值。出于同样的原因,你不会写

if x == 1:
    y == 1
elif x == 2:
    y == 2
# ... etc. ad infinitum for every possible integer value of x

你也不应该对布尔也这样做。最后,我们可以而且应该使用逻辑andor来连接布尔条件。

def match(pList):
    b = []
    z = len(pList)-1
    for x in range(z):
        b.append([pList[x][0],0])
    for x in range(z):
        isValid = False
        q = p = 0
        while not isValid:
            q = random.randint(0, z)
            isValid = not pList[q][1]
        isMatch = False
        while not isMatch:
            if not pList[q][1]:
                isValid = False
                while not isValid:
                    p = random.randint(0,z)
                    isValid = not pList[p][2] and (q != p)
                b[q][1] = pList[p][0]
                isMatch = True
    return b

我的下一步将是修复列表索引。索引到列表通常不是你想要的,实际上它引入了一个bug。很明显,你想要遍历每一行&#34;行&#34; pList;但是range(z)会为您提供从0z-1的数字,因此在计算len(pList)时从z减去1是不正确的。例如,如果pList包含5个元素,您将计算z = 4,并生成range(z) = [0, 1, 2, 3]。您永远不会访问pList[4]b只会有4个元素。

从根本上说,您正在使用z做两件事。一个是循环运行多次,因为有&#34;行&#34;在pList中,和(在第一个循环中)对每个&#34;行&#34;做一些事情。要做到这一点

这非常重要: range不是魔术,它与for循环没有特殊的连接。它只是一个产生数字列表的函数。在Python中,for循环直接为您提供元素。所有这些索引废话只是 - 废话,最好留给能力较弱的语言。如果你想对列表的每个元素做一些事情,那么对列表中的每个元素执行某些操作,通过编写循环遍历列表的每个元素的代码。直。不是在一些单独的索引列表上,然后您可以使用它们索引回原始索引。这让你的事情变得复杂。

使用z做的第二件事是生成一个可能的索引的随机数,以便您可以索引到pList以获得随机行。换句话说,您只想选择一个随机行。所以只选择一个随机行random模块直接提供此功能:该函数称为random.choice,它完全听起来像。

这里有一个小问题:原始代码比较p == q,即比较两个随机选择的列表索引是否相等。如果我们不再编制索引,那么我们就没有要比较的索引。要解决这个问题,我们需要了解最初的目的是什么:检查新选择的行是否实际上是旧选择的行。同样,我们通过直接检查来简化:我们选择新行而不是新索引,然后查看它是否is旧索引。

我们还遇到一个问题,我们需要从b中选择与我们之前已标识为pList的{​​{1}}中的哪一行相对应的行。为了解决这个问题,我们可以在q行的同时选择b行。这有点棘手:我的方法是创建一对行列表 - 在每对中,将有pList行,然后是b行。这并不需要任何复杂的事情 - 实际上有一个内置函数可以将pListb完全拼接在一起:它被称为pList 。无论如何,从行对列表中选择了一个行对,我们只需要将两行解包为两个变量 - 使用您首先错误使用的zip语法,因为事实证明。这就是它的用途。

通过这些更改,我们实际上可以完全摆脱q, p = ...pq。这很好,因为它完全不清楚那些名字本来应该是什么意思。

z

进行更合理清理的时间。在第一个while循环中,我们将继续循环,直到def match(pList): b = [] for row in pList: b.append([row[0], 0]) for row in pList: isValid = False while not isValid: first_row, b_row = random.choice(zip(pList, b)) isValid = not first_row[1] isMatch = False while not isMatch: if not first_row[1]: isValid = False while not isValid: second_row = random.choice(pList) isValid = not second_row[2] and (first_row is not second_row) b_row[1] = second_row[0] isMatch = True return b 变为真。也就是说,直到isValid变为真。在第二个while循环中,not first_row[1]永远不会被更改,因此,当循环开始时first_row为真,它将在整个时间内保持为真。因此,if-check是完全没必要的。

一旦消失,我们发现第二个while循环实际上也完全没用:它将循环not first_row[1],即直到 while not isMatch。什么是isMatch?好吧,在我们开始循环之前,它是isMatch,在循环结束时,它是False。总是。所以我们知道这段代码只运行一次。我们进入循环,转到最后,将True设置为true,然后退出,因为刚刚设置为true的isMatch为真。只运行一次的代码不需要循环;它只是代码。

我在这里做的另一件事是在我们完成时将isMatch循环转换为仅仅while isValid来清理break循环。 break不是邪恶的(也不是continue)。它们实际上简化了我们对布尔值的思考,因为我们不再检查not isValid(强调not);我们只是直接与我们分配给isValid的内容进行比较。这意味着我们也摆脱了isValid变量,这也是实际上并没有告诉我们的名称

def match(pList):
    b = []
    for row in pList:
        b.append([row[0], 0])
    for row in pList:
        while True:
            first_row, b_row = random.choice(zip(pList, b))
            if not first_row[1]:
                break
        while True:
            second_row = random.choice(pList)
            if not second_row[2] and (first_row is not second_row):
                break
        b_row[1] = second_row[0]
    return b

最后一件事:我们可以更清洁地构建b。通过附加元素来建立列表是一个吸盘游戏。 不要告诉Python如何构建列表。它知道如何。相反,要求提供符合您规范的列表,并使用列表理解。这比显示的更简单(如果您需要解释,请咨询Google),所以我会继续为您提供一个版本:

def match(pList):
    b = [[row[0], 0] for row in pList]
    for row in pList:
        while True:
            first_row, b_row = random.choice(zip(pList, b))
            if not first_row[1]:
                break
        while True:
            second_row = random.choice(pList)
            if not second_row[2] and (first_row is not second_row):
                break
        b_row[1] = second_row[0]
    return b

从现在开始,如果不理解你实际在做什么,很难纠正或改进任何事情。完成所有这些工作后,我仍然不知道!

你设置它的方式,你选择一个随机行,就像有行一样多次 - 但你仍然可以选择重复。那是你真正想要的吗?或者你想以随机顺序选择每一行?无论如何,以随机顺序执行此操作的重要性是什么?

选择第一行后,选择要匹配的随机第二行。你真的想要每一行有一个随机行吗?或者您想尝试所有可能的行对吗?

无论如何,这些数据究竟是什么?输出b数据代表什么? pList开头究竟是什么,为什么称为pList?你是什​​么&#34;匹配&#34;使用此match函数?老实说,我无法想象。