我不明白这个KeyError?

I don't understand this KeyError?

我正在做这个挑战,我的任务是编写一个刽子手游戏 - 我应该减少 set.The 游戏规则中的单词范围,你可以尝试 8 次太猜了,否则你会 lose.If 用户不止一次输入同一个字母会弹出一条消息,说明他已经这样做了 - 我已经使用集合作为处理这部分游戏的一种方式.下面是我的代码:


word_list = ["python", "java", "kotlin", "javascript"]
word = random.choice(word_list)
word_set = set(word)

hidden = []
for i in word:
    hidden.append("-")
# print(hidden)


print("H A N G M A N")

count = 0
while(count < 8):
    print()
    print("".join(hidden))
    guess = input("Input a letter: ")
    if guess in word:
        if guess not in word_set:
            print("No improvements")
            count += 1
        else:
            for i in range(len(word)):
                if word[i] == guess:
                    print(word_set)
                    word_set.remove(word[i])
                    hidden[i] = word[i]
                    if word_set == set():
                        print()
                        print(word)
                        print("You guessed the word!")
                        print("You survived!")
    else:
        print("No such letter in the word")
        count += 1

print("You are hanged!")

我面临的主要问题是一个错误告诉我 'a',特别是 'a' 是一个关键错误,如下所示:Traceback (most recent call last): File "/Users/laipinhoong/Desktop/learnpython.py/learning.py", line 29, in <module> word_set.remove(word[i]) KeyError: 'a'

The problem appears when the chosen word has the same letter more once.在这种情况下,由于您遍历了单词 (for i in range(len(word))) 中的所有字母,您将尝试从集合 word_set 中删除该单词几次(与该字母在单词中出现的次数一样多)但是 word_set 将只有一次此字母,因为集合是唯一的集合。因此,在第二次尝试从 javascriptjava 中删除 a 时,word_set.remove(word[i]) 将失败,因为集合将不再包含此字母。

为了防止出错,尝试使用: word_set.discard(word[i]) 代替。在这种情况下,如果该字母存在,将被删除,如果不存在,则不会引发异常。

每次您选择单词中重复的字母时,您的关键错误都会发生。当你在 for i in range(len(word)): 循环中执行 word_set.remove(word[i]) 并且 word 在多个 i 处有相同的字母时,当它击中第二个 [=13= 时会发生此键错误]对应单词中的那个字母。如果您在 python tutor.

中单步执行代码,这对您来说会更有意义

您需要了解您的代码的作用:

当您从 word_set.remove(word[i]) 中删除一个字符时。这将删除它,但在第二次迭代时它找不到该字符,因此它会抛出密钥错误,因为它找不到已删除的密钥。

尝试像这段代码一样添加一个 if 条件,以在删除之前检查密钥是否存在,如果不存在,实际上可以绕过,避免出现密钥错误

import random

word_list = ["python", "java", "kotlin", "javascript"]
word = random.choice(word_list)
print(word)
word_set = set(word)

hidden = []
for i in word:
    hidden.append("-")
#print(hidden)


print("H A N G M A N")

count = 0
while(count < 8):
    print()
    print("".join(hidden))
    guess = input("Input a letter: ")
    if guess in word:
        if guess not in word_set:
            print("No improvements")
            count += 1
        else:
            for i in range(len(word)):
                if word[i] == guess:

                    if word in word_set:
                        word_set.remove(word[i])
                    hidden[i] = word[i]
                    if word_set == set(hidden):
                        print()
                        print(word)
                        print("You guessed the word!")
                        print("You survived!")
    else:
        print("No such letter in the word")
        count += 1

print("You are hanged!")

您尝试多次删除同一个字母,因为您迭代了 word - 而是迭代了它的一组字母。您还可以预先计算每个字母在字典中的位置,然后将其用于 "fill in the gaps",如下所示:

word = "javascript"
seen = set()           # letters that were guessed get added here 
letters = set(word)    # these are the letters to be guessed

hidden = ["_" for _ in word]   # the output

positions = {l:[] for l in letters }  # a dictionary letter => positions list
for idx,l in enumerate(word):         # add positions of each letter into the list
    positions[l].append(idx)

print("H A N G M A N")

count = 0
while count < 8:
    print()
    print("".join(hidden))

    # allow only 1-letter guesses
    guess = input("Input a letter: ").strip()[0]

    # if in seen it is a repeat, skip over the remainder of the code
    if guess in seen:
        print("Tried that one already.")
        continue

    # found a letter inside your word
    if guess in positions:    
        # update the output list to contain this letter
        for pos in positions.get(guess):
            hidden[pos]=guess
        # remove the letter from the positions list 
        del positions[guess]

    else: # wrong guess
        count += 1
        print("No improvements: ", 8-count, "guesses left.")

    # remember the seen letter    
    seen.add(guess) 

    # if the positions dictionary got cleared, we have won and found all letters
    if not positions:    
        print(word)
        print("You guessed the word!")
        print("You survived!")
        break

# else we are dead
if count==8:
    print("You are hanged!")

输出:

__________
Input a letter: 
j_________
Input a letter: 
ja_a______
Input a letter: 
java______
Input a letter: 
javas_____
Input a letter: 
javasc____
Input a letter: 
javascr___
Input a letter: 
javascri__
Input a letter: 
javascrip_

# on bad inputs:
No improvements:  7 guesses left.

# on win
javascript
You guessed the word!
You survived!

# on loose
You are hanged!

Set.remove() 如果您要删除的项目不属于集合,则抛出 KeyError。

你的情况是word_set和单词的字母不一样造成的。

例如如果word = java,则word_set = (j, a, v)

并且由于您是在单词而不是 word_set 上循环,您的代码将尝试从 word_set 中删除字母 'a' 两次,这将导致 keyError