如何为Python游戏设置用户输入最长时限?
单词复述游戏:输入限时5秒的实现问题与解决
需求说明
要做一个简单的单词复述游戏:
- 系统依次给出单词,用户需在5秒内输入完全相同的单词
- 输入正确则进入下一轮,超时或输入错误则游戏结束
- 用户可以提前输入(比如2秒内完成),无需等待满5秒
初始无时限代码
for word in ["banana","earth","turtle","manchester","coctail","chicken"]: # 用户最多5秒输入单词,提前完成可直接进入下一轮,超时则游戏结束 user_input = input(f"Type word '{word}': ") # 输入正确则进入下一轮 if(user_input==word): continue # 输入错误则结束游戏 else: print("You lost") break
尝试的threading.Timer实现(存在问题)
import threading class NoTime(Exception): pass def count_time(): raise NoTime for word in ["banana","earth","turtle","manchester","coctail","chicken"]: try: # 创建5秒后抛出异常的计时器 timer = threading.Timer(5,count_time) timer.start() user_input = input(f"Type word '{word}': ") # 若提前输入,取消计时器避免不必要的异常 timer.cancel() if user_input==word: print("Correct") else: print("Incorrect, you LOSE!") break except NoTime: print("You run out of time, you lose") break
出现的错误信息
回溯(最近的调用最后): 文件 "C:\Users\papit\AppData\Local\Programs\Python\Python311\Lib\threading.py", 第1038行, 在 _bootstrap_inner中 self.run() 文件 "C:\Users\papit\AppData\Local\Programs\Python\Python311\Lib\threading.py", 第1394行, 在 run中 self.function(*self.args, **self.kwargs) 文件 "C:\Users\papit\OneDrive\Pulpit\Programming\Python Bro Course\Math\second\threading_training.py", 第7行, 在 count_time中 raise NoTime NoTime
问题原因
子线程中抛出的异常无法被主线程的try-except捕获。threading.Timer启动的是独立子线程,count_time函数里的NoTime异常是在子线程上下文触发的,主线程的异常处理机制无法感知到这个异常,所以会直接打印堆栈信息,而不是进入except NoTime分支执行游戏结束逻辑。
解决方案:跨平台实现方式
用threading.Thread读取输入,配合threading.Event标记输入完成状态,主线程通过wait()设置超时时间,完美解决跨平台的输入限时问题:
import threading words = ["banana", "earth", "turtle", "manchester", "coctail", "chicken"] for word in words: input_received = threading.Event() user_input = None # 定义读取输入的线程函数 def get_user_input(): nonlocal user_input user_input = input(f"输入单词 '{word}': ").strip() input_received.set() # 标记输入已完成 # 启动输入线程 input_thread = threading.Thread(target=get_user_input) input_thread.start() # 主线程等待最多5秒:要么输入完成,要么超时 if not input_received.wait(timeout=5): # 超时逻辑 print("\n你超时了,游戏结束!") break else: # 输入完成,判断对错 if user_input == word: print("正确!进入下一轮") else: print(f"错误!你输入的是'{user_input}',游戏结束") break else: # 所有单词都正确完成 print("恭喜你,所有单词都答对了!游戏通关!")
代码说明
input_received是线程安全的事件对象,用来标记用户是否完成输入- 单独启动一个线程执行
get_user_input,避免input()阻塞主线程的超时判断 - 主线程通过
input_received.wait(5)等待最多5秒:- 如果5秒内用户完成输入,
input_received会被设置,wait()返回True,进入输入校验逻辑 - 如果5秒超时,
wait()返回False,触发超时结束游戏的逻辑
- 如果5秒内用户完成输入,
- 最后添加
for-else分支,处理所有单词都答对的通关场景
另一种Unix/Linux专属方案:用select实现
如果你的程序只在Unix/Linux环境运行,可以用select模块直接监听标准输入,无需额外线程:
import sys import select words = ["banana", "earth", "turtle", "manchester", "coctail", "chicken"] for word in words: print(f"输入单词 '{word}': ", end='', flush=True) # 监听stdin,超时5秒 ready, _, _ = select.select([sys.stdin], [], [], 5) if ready: # 有输入,读取并处理 user_input = sys.stdin.readline().strip() if user_input == word: print("正确!进入下一轮") else: print(f"\n错误!你输入的是'{user_input}',游戏结束") break else: # 超时 print("\n你超时了,游戏结束!") break else: print("恭喜你,所有单词都答对了!游戏通关!")
内容的提问来源于stack exchange,提问作者Paweł Michoń
相关产品推荐
相关产品推荐

