You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 19:50:17