Python测验程序偶发KeyError: None错误求助(学校项目)
Python测验程序KeyError: None问题解决
问题现象
偶尔运行程序时出现以下错误:
Traceback (most recent call last): File "main.py", line 55, in <module> random.shuffle(questions[question]["answers"]) KeyError: None
多数情况下程序能正常运行,仅偶尔触发该错误。
完整代码
# Lia's quiz. Questions are subject to change # Used https://www.randomtriviagenerator.com/ to generate the questions and answers import random # The questions dictionary. Each question has a list of possible answers, the correct answer, a comment, and the amount of points you get for it. I'll add more later questions = { 0: { "question": "Which country technically fought a war agaisnt a type of bird?", "answers": ['Angola', 'Australia', 'Venezuela', 'Pakistan'], "correct": "Australia", "comment": "The \"Emu\" war was fought in Australia between November and December 1932. The Emus won.", "points": 1 }, 1: { "question": "What sea lies between Greece and Turkey?", "answers": ['Ionian Sea', 'Aegean Sea', 'Mediterranean Sea', 'Adriatic Sea'], "correct": "Aegean Sea", "comment": "The Aegean Sea lies between the east coast of Greece and the west coast of Turkey.", "points": 1 }, 2: { "question": "Complete the name of the 2012 album by Lana Del Rey: Born to...", "answers": ['...Live', '...Die', '...Love', '...Cry'], "correct": "...Die", "comment": "Born to Die is the second studio album and major-label debut by American singer-songwriter Lana Del Rey, released in January 2012.", "points": 1 }, } # Set the score to zero score = 0 # Get a random question, and make sure it hasn't been asked before questions_done = [] def question_randomiser(): question = random.randint(0, 2) if (questions_done.count(question) > 0): question_randomiser() return questions_done.append(question) return question # Main loop, repeats as many times as you want. I intentionally made it not rely on the amount of questions there are, so each quiz is a little different. for i in range(3): # Get a random question, and make sure it hasn't been asked before question = question_randomiser() # Shuffle the answers in a different order random.shuffle(questions[question]["answers"]) a = questions[question]["answers"][0] b = questions[question]["answers"][1] c = questions[question]["answers"][2] d = questions[question]["answers"][3] # Ask the question print(f"\n\n{questions[question]['question']}") # Get the user's answer ans = input(f"1. {a}, 2. {b}, 3. {c}, 4. {d}. \n") # Check if the answer is valid if (ans.isnumeric() == 0): print( "\nERROR: The value you input must be a number between 1 and 4, written in decimal form with no punctuation. Try again: \\033[F" ) continue ans = int(ans) if (ans > 4 or ans < 1): print( "\nERROR: The value you input must be a number between 1 and 4, written in decimal form with no punctuation. Try again:\\033[F" ) continue # Check if the answer is correct. if ((ans + -1) == questions[question]["answers"].index( questions[question]["correct"])): print(f"Correct. {questions[question]['comment']}\nPlus {questions[question]['points']} point(s).") else: print(f"Incorrect. {questions[question]['comment']}")
问题原因
错误根源在question_randomiser函数的递归逻辑:当随机到已存在于questions_done中的问题时,函数递归调用自身,但没有返回递归调用的结果,导致当前函数执行完question_randomiser()后直接return,最终返回None。当主循环中question变量为None时,访问questions[question]就会触发KeyError: None。
修复方案
方案1:修复递归返回值
修改question_randomiser函数,在递归调用时返回结果:
def question_randomiser(): question = random.randint(0, 2) if questions_done.count(question) > 0: # 递归调用时返回结果 return question_randomiser() questions_done.append(question) return question
方案2:改用循环实现(更推荐)
递归在这里没必要,用循环可以避免潜在的递归深度问题,逻辑更清晰:
def question_randomiser(): while True: question = random.randint(0, 2) if question not in questions_done: questions_done.append(question) return question
方案3:直接获取不重复的问题列表(最优)
如果要一次性获取所有不重复的问题,可以用random.sample直接打乱问题索引,主循环直接遍历结果,省去单独的随机函数:
# 主循环前先打乱所有问题索引 shuffled_questions = random.sample(list(questions.keys()), len(questions)) for question in shuffled_questions: # 后续逻辑不变,直接使用question变量 random.shuffle(questions[question]["answers"]) # ... 其余代码 ...
这种方式完全避免了重复判断的逻辑,代码更简洁高效。
额外优化建议
- 把
questions_done.count(question)改成question not in questions_done判断,时间复杂度从O(n)降到O(1),效率更高。 - 用
len(questions)替代固定数字2,新增问题后不用手动修改随机范围。
内容的提问来源于stack exchange,提问作者lia-young-07
相关产品推荐
相关产品推荐

