0

我正在自学 Python 3.2,并且正在尝试制作一个程序来匹配名称列表。pList 是一个多维列表,第 0 列有一个字符串,第 1 列有一个整数,第 2 列有一个布尔值。但是,每当我尝试调用此函数时(仅当列表中的行数为偶数时才会运行),我得到一个类型错误。

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
4

2 回答 2

5

这是你的构造:

q, p = 0

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

采用:

q = p = 0

反而。

于 2012-06-04T16:08:28.563 回答
3

你的逻辑复杂了,以至于我必须进行几次传递才能缩小规模并向你展示你做错了什么。

首先,正如其他人所指出的,我们将修复实际报告的错误。同时,我们将应用一个简单的原则:不要与布尔文字比较。你不会说“如果真的在下雨,我需要一把伞”。你说“如果下雨,我需要一把伞”。所以去掉多余的东西。if isValid清楚if 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

我的下一步将是修复列表索引。索引到列表中通常不是你真正想要的,实际上它在这里引入了一个错误。很明显,您想要遍历 ; 的每一“行” pList。但是range(z)给你从0z-1包含的数字,所以len(pList)在计算中减去 1 是不正确的z。例如,如果pList有 5 个元素,您将计算z = 4并产生range(z) = [0, 1, 2, 3]。您将永远无法访问pList[4],并且b只有 4 个元素。

z从根本上说,您正在用 做两件事。一个是使循环运行的次数与 中的“行”一样多pList,并且(在第一个循环中)对每个“行”执行一些操作。去做这个

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

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

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

我们还有一个问题,我们需要从中选择一个对应的行,b该行对应于pList我们之前识别为 的行q。为了解决这个问题,我们可以在选择b行的同时选择pList行。这有点棘手:我的方法是制作成对的行列表 - 在每一对中,会有一行 from b,然后是一行 from pList。这不需要任何复杂的东西——实际上有一个内置函数可以完全按照我们的意愿拼接b在一起pList:它被称为zip. 无论如何,从该行对列表中选择了一个行对,我们只需将这两行解压缩为两个变量 - 使用q, p = ...事实证明,您首先错误地使用了语法。这就是它的用途。

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

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

是时候进行一些更合乎逻辑的清理了。在第一个 while 循环中,我们将继续循环直到isValid变为 true。也就是说,直到not first_row[1]成为真的。在第二个 while 循环中,first_row永远不会改变,因此,由于not first_row[1]循环开始时为真,因此它将始终保持为真。因此,完全没有必要进行 if-check。

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

我将在这里做的另一件事是通过在我们完成while isValid后将它们转换为刚刚输出来稍微清理循环。不是邪恶的(也不是)。它们实际上简化了我们对布尔值的思考,因为我们不再检查(强调);我们只是直接与我们分配给的内容进行比较。这意味着我们也摆脱了变量,这又是一个实际上并没有告诉我们太多信息的名称。breakbreakcontinuenot isValidnotisValidisValid

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 如何构建列表。它知道怎么做。相反,要求一个符合您的规范的列表,并带有列表理解。这比解释更简单(如果你需要解释,请咨询谷歌),所以我会继续给你一个版本:

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?您与此match功能“匹配”什么?老实说,我无法想象。

于 2012-06-04T18:08:12.807 回答