簡體   English   中英

遍歷列表中的Python TypeError

[英]Python TypeError in traversing a list

我正在自學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

這是你的構造:

q, p = 0

它試圖通過迭代來解壓縮單個int。 那不是有效的Python語法。 我想錯誤可能會更好。

采用:

q = p = 0

代替。

您已經使邏輯變得非常復雜,以至於我將不得不進行多次遍歷以減小其尺寸並向您展示您在做錯什么。

首先,如其他人所述,我們將修復實際報告的錯誤。 同時,我們將應用一個簡單的原理: 不要與布爾文字進行比較 您不會說“如果確實在下雨,我將需要一把雨傘”。 您說“如果正在下雨,我需要一把雨傘”。 所以切掉多余的東西。 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值的檢查)之間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-1range(z)數字,因此在計算zlen(pList)中減去1是不正確的。 例如,如果pList有5個元素,則將計算z = 4 ,並產生range(z) = [0, 1, 2, 3] 您將永遠不會訪問pList[4] ,並且b將只有4個元素。

從根本上講,您正在使用z做兩件事。 一種是使循環運行的次數與pList中“行”的pList ,並且(在第一個循環中)對每個“行”執行某項操作。 去做這個

這非常重要: range不是魔術,並且它與for循環沒有特殊聯系 它只是一個產生數字列表的函數。 在Python中, for循環直接為您提供元素 所有這些對索引的廢話就是廢話,最好留給能力較弱的語言使用。 如果要對列表的每個元素進行操作 ,請通過編寫遍歷列表的每個元素的代碼對列表的每個元素進行操作 直。 不要超過一些單獨的索引列表,然后使用這些索引重新索引到原始索引。 這使事情變得復雜。

使用z的第二件事是生成一個可能的索引隨機數,以便您可以索引pList以獲得隨機行。 換句話說,您只想選擇一個隨機行。 因此, 只需選擇一個隨機行 random模塊直接提供了此功能:該函數稱為random.choice ,它的功能完全像聽起來的那樣。

這里有一個小障礙:原始代碼比較p == q ,即比較兩個隨機選擇的列表索引是否相等。 如果我們不再編制索引,那么就沒有索引可比較了。 要解決此問題,我們需要了解最初的目的是: 檢查新選擇的行是否實際上又是舊選擇的行 再次,我們通過直接檢查來簡化:我們選擇新行而不是新索引,然后查看它is為舊索引。

還有一個問題是,我們需要從b中選擇一個對應的行,該行對應於pList我們先前將其標識為q任何行。 為了解決這個問題,我們可以在選擇pList行的同時選擇b行。 這有點棘手:我的方法是制作成對的行列表-在每對中,從b開始一行,然后從pList一行。 這不需要任何復雜的操作-實際上,有一個內置函數可以將bpList完全按照我們的意願縫合在一起:它稱為zip 無論如何,已經從該行對列表中選擇了一個行對,我們只需要將兩行解壓縮為兩個變量-首先使用錯誤的q, p = ...語法即可,因為原來。 那就是它的目的。

通過這些更改,我們實際上可以完全擺脫pqz 很好,因為無論如何這些名字到底意味着什么還不清楚。

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]變為true為止。 在第二個while循環中, first_row從未更改,因此,由於在循環開始時not first_row[1]為true,因此在整個過程中它將保持為true。 因此,完全不需要if-check。

一旦結束,我們發現第二個while循環實際上也完全沒有用:它將while not isMatch 之前循環, 直到 isMatch 為止 什么是isMatch 好吧,在我們開始循環之前,它是False ,而在循環結束時它是True 總是。 因此,我們知道這段代碼將只運行一次。 我們進入循環,到最后,將isMatch設置為true,然后退出,因為剛剛設置為true的isMatch為true。 只運行一次的代碼不需要循環; 這只是代碼。

我在這里要做的另一件事是,將while isValid循環稍微轉換一下,以將其轉換為結束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 您與此match功能“匹配”什么? 老實說,我無法想象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM