Python打字速度测试:线程实现及循环超时未停止问题修复
打字速度测试工具:循环停止修复与线程使用指南
一、先解决你的循环不停止问题
你的代码里有两个关键问题导致时间到了还停不下来:
- 外层
while循环用的是初始化时的currenttime,这个值自始至终没更新过——不过你内部用now_time做了判断,这个问题不算致命; - 嵌套的
for循环会把所有单词挨个跑完,而且input()是阻塞调用——哪怕时间早就到了,程序也得等你把当前单词输完,把整个列表遍历完才会退出。
下面是修复后的代码,顺便把你要的随机单词功能加上:
import datetime import random word_list = ['hello', 'darkness', 'my', 'old', 'friend', 'fox'] print("You have 1 minute to type all the words you can") start = input('Press y to start or n to exit: ').lower() wrong = [] correct = [] total = [] if start == 'y': test_duration = 60 end_time = datetime.datetime.now() + datetime.timedelta(seconds=test_duration) print(f"Test started! You have {test_duration} seconds.") while datetime.datetime.now() < end_time: # 每次循环先检查剩余时间 remaining = (end_time - datetime.datetime.now()).total_seconds() if remaining <= 0: print('\nTime is up!') break # 随机选一个单词 current_word = random.choice(word_list) print(f"\nType this: {current_word}") # 这里还是会等你输入完,但至少每次输入前会确认时间 user_input = input().strip() total.append(current_word) if user_input == current_word: correct.append(current_word) else: wrong.append(current_word) # 计算WPM(标准算法:每分钟输入单词数,按每个单词5字符的统计方式) wpm = len(total) / (test_duration / 60) if test_duration else 0 accuracy = (len(correct)/len(total))*100 if total else 0 print(f'\n--- Results ---') print(f'Total words typed: {len(total)}') print(f'Correct: {len(correct)} | Wrong: {len(wrong)}') print(f'WPM: {round(wpm, 2)}') print(f'Accuracy: {round(accuracy, 2)}%')
二、要不要用threading?
不用线程的局限
上面的修复代码能正常工作,但有个小瑕疵:如果在最后几秒你开始输入一个单词,哪怕时间到了,程序也得等你输完才会结束。这是因为input()会卡住主线程,没法中途打断。
用线程的好处
如果想实现时间一到立刻终止输入提示的效果,就得用线程。我们可以开一个线程专门计时,主线程处理输入,计时线程到点后设置一个标志,主线程根据这个标志决定是否继续。
给你一个线程版的示例:
import datetime import random import threading import time word_list = ['hello', 'darkness', 'my', 'old', 'friend', 'fox'] print("You have 1 minute to type all the words you can") start = input('Press y to start or n to exit: ').lower() wrong = [] correct = [] total = [] time_expired = False # 标记时间是否到了 def countdown_timer(duration): global time_expired time.sleep(duration) time_expired = True print('\nTime is up!') if start == 'y': test_duration = 60 # 启动计时线程,daemon=True保证主线程结束时它也跟着结束 threading.Thread(target=countdown_timer, args=(test_duration,), daemon=True).start() print(f"Test started! You have {test_duration} seconds.") while not time_expired: current_word = random.choice(word_list) print(f"\nType this: {current_word}") # 用线程处理输入,避免主线程一直被input()卡住 user_input = None def get_user_input(): nonlocal user_input user_input = input().strip() input_thread = threading.Thread(target=get_user_input) input_thread.start() # 每秒检查一次时间是否到了,不用一直等输入 input_thread.join(timeout=1) if time_expired: break if user_input is not None: total.append(current_word) if user_input == current_word: correct.append(current_word) else: wrong.append(current_word) # 计算结果 wpm = len(total) / (test_duration / 60) if test_duration else 0 accuracy = (len(correct)/len(total))*100 if total else 0 print(f'\n--- Results ---') print(f'Total words typed: {len(total)}') print(f'Correct: {len(correct)} | Wrong: {len(wrong)}') print(f'WPM: {round(wpm, 2)}') print(f'Accuracy: {round(accuracy, 2)}%')
这个版本里,计时线程到点后会把time_expired设为True,主线程每秒检查一次这个标志,一旦时间到了就立刻停止等待输入。
总结
- 如果你能接受“时间到后等用户输完当前单词再结束”,完全不用线程,修复循环逻辑就够了;
- 如果你想要更丝滑的体验,时间到了立刻终止输入,可以用线程来实现。
内容的提问来源于stack exchange,提问作者TwinkleTwinkle
相关产品推荐
相关产品推荐

