Python Discord API 投票Bot开发:实现24小时定时投票结果自动统计
适配现有代码的24小时投票计时器+自动统计落地方案
核心前置注意事项
- 禁止在指令回调中使用
time.sleep(86400)做定时,该操作属于阻塞式等待,会直接卡死Bot的整个事件循环,导致所有指令、交互完全无响应 - 采用异步等待方案实现单条投票的独立24小时计时,全程不影响Bot正常处理其他用户消息
分步实现流程(完全兼容已完成的基础投票发消息、加反应逻辑)
- 第一步:建立活动投票的映射存储
新增全局字典存储正在计时中的投票,避免不同投票的消息、结果统计混淆:
执行active_polls = {}+poll指令时,完成投票消息发送、添加👍/👎初始反应后,立刻将该条投票消息的ID作为key,关联消息对象、所属频道存入字典 - 第二步:为每条投票绑定独立异步定时任务
引入异步任务创建工具,给每条新投票单独启动计时协程,24小时等待过程不占用Bot的事件循环资源:
发完投票消息后,直接启动该定时任务:import asyncio async def end_poll_timer(poll_message, channel): # 异步等待24小时(共86400秒) await asyncio.sleep(86400) # 计时结束后,将该投票从活动列表移除 if poll_message.id in active_polls: del active_polls[poll_message.id] # 触发结果统计流程 await calculate_poll_result(poll_message, channel)asyncio.create_task(end_poll_timer(poll_message, ctx.channel)) - 第三步:修复统计逻辑缺陷的结果计算函数
针对性解决旧逻辑中“把Bot自己的初始反应算入票数、用到缓存旧数据漏统计最新反应”的问题:async def calculate_poll_result(poll_message, channel): # 从服务器拉取最新的投票消息,替换本地缓存的旧数据 latest_message = await channel.fetch_message(poll_message.id) up_votes = 0 down_votes = 0 # 遍历消息上的所有反应 for reaction in latest_message.reactions: # 匹配👍反应 if str(reaction.emoji) == "👍": # 遍历所有点反应的用户,过滤掉Bot账号本身,避免把初始反应算入票数 user_list = [user async for user in reaction.users() if not user.bot] up_votes = len(user_list) # 匹配👎反应 elif str(reaction.emoji) == "👎": user_list = [user async for user in reaction.users() if not user.bot] down_votes = len(user_list) # 生成对比结果 result_content = f"投票「{latest_message.content}」已到期\n👍 支持票数:{up_votes}\n👎 反对票数:{down_votes}\n" if up_votes > down_votes: result_content += "✅ 支持方获得最终胜利" elif down_votes > up_votes: result_content += "❌ 反对方获得最终胜利" else: result_content += "⚖️ 双方票数持平" # 将结果发送到原投票所在频道 await channel.send(result_content)
常见踩坑补全
- 不要直接使用
reaction.count属性统计票数,该属性数值包含Bot自身添加的初始反应,会导致基础票数虚高1票 - 统计前必须调用
fetch_message拉取服务器端的最新消息状态,不能直接使用之前发送消息时返回的旧对象,避免漏掉计时最后时刻用户的投票反应 - 新手开发阶段无需额外做数据库持久化,内存字典存储的投票信息足够支撑基础功能运行,等后续功能迭代再适配重启后恢复计时的能力即可
内容的提问来源于stack exchange,提问作者Justin Shi
相关产品推荐
相关产品推荐

