discord.py中列表append操作失效问题求助
问题排查与修复方案
兄弟,你遇到的核心问题太明显了——每次触发.spam命令时,你都在重新创建一个新列表,直接把之前存的服务器ID覆盖了,自然不会追加新ID!下面我一步步给你拆解问题,再给出完整的修复代码。
1. 列表覆盖的根源
看你on_message里这段代码:
if message.content.startswith('.spam'): global thislist thislist = [message.guild.id]
每次收到.spam消息,你都用thislist = [message.guild.id]创建了一个全新的列表,之前的内容直接被丢弃。正确的做法是先初始化一次列表,然后用append()添加新ID。
2. 修复列表追加逻辑
首先把列表初始化移到全局作用域(只在bot启动时执行一次),然后在.spam触发时判断ID是否已存在,不存在就追加:
# 全局初始化存储服务器ID的列表,只执行一次 running_guilds = [] # 然后修改on_message里的.spam处理: if message.content.startswith('.spam'): guild_id = message.guild.id if guild_id not in running_guilds: running_guilds.append(guild_id) print(running_guilds) print(len(running_guilds))
3. 修复多服务器冲突的stop逻辑
你原来用全局变量s和z来控制停止,这在多服务器场景下会炸锅——比如A服务器执行stop,会把B服务器的spam也停了。改用字典按服务器ID单独控制状态才是正确的:
# 全局字典,键是服务器ID,值是是否停止spam spam_status = {} # 修改on_message里的.stop处理: if message.content.startswith('.stop'): guild_id = message.guild.id spam_status[guild_id] = True # 然后修改spam命令的循环逻辑: @client.command() @commands.has_role('discordpy') async def spam(ctx, *, my_id): print("it worked") await asyncio.sleep(5) # 这里必须替换time.sleep,不然会阻塞整个bot x = 1 guild_id = ctx.guild.id spam_status[guild_id] = False # 标记当前服务器spam为运行中 while not spam_status.get(guild_id, False): myid = str(my_id) await ctx.channel.send(f"{myid} x {x}") print(x) x += 1 await asyncio.sleep(0.5) # 同样替换time.sleep
4. 修复stopbot命令的错误
你原来的self.isrunning = False完全没用,应该用client.close()来关闭bot:
@client.command() @commands.has_role('discordpy') async def stopbot(ctx): await ctx.send("Bot正在关闭...") await client.close()
完整修复后的代码
整合所有修改,还优化了变量名让代码更易懂:
import discord, pyautogui, asyncio from discord.ext import commands client = commands.Bot(command_prefix = '.') # 存储正在运行spam的服务器ID running_guilds = [] # 存储每个服务器的spam停止状态 spam_status = {} @client.event async def on_ready(): print('We have logged in as {0.user}'.format(client)) @client.event async def on_message(message): if message.author == client.user: return if message.content.startswith('.spam'): guild_id = message.guild.id if guild_id not in running_guilds: running_guilds.append(guild_id) print(running_guilds) print(len(running_guilds)) if message.content.startswith('.stop'): guild_id = message.guild.id spam_status[guild_id] = True await client.process_commands(message) @client.command() @commands.has_role('discordpy') async def spam(ctx, *, my_id): print("it worked") await asyncio.sleep(5) x = 1 guild_id = ctx.guild.id spam_status[guild_id] = False if guild_id not in running_guilds: running_guilds.append(guild_id) while not spam_status.get(guild_id, False): myid = str(my_id) await ctx.channel.send(f"{myid} x {x}") print(x) x += 1 await asyncio.sleep(0.5) # 停止后从运行列表移除 if guild_id in running_guilds: running_guilds.remove(guild_id) @client.command() @commands.has_role('discordpy') async def stop(ctx): guild_id = ctx.guild.id spam_status[guild_id] = True await ctx.send("Spam已停止!") if guild_id in running_guilds: running_guilds.remove(guild_id) @client.command() @commands.has_role('discordpy') async def stopbot(ctx): await ctx.send("Bot正在关闭...") await client.close() client.run('你的Token')
重要提醒
- 绝对不要用
time.sleep()在discord.py的异步代码里!它会阻塞整个bot的事件循环,导致bot无法响应任何消息和命令,必须用asyncio.sleep()代替。 - 全局变量要谨慎使用,像多服务器场景下,用字典按服务器ID隔离状态才不会出冲突。
内容的提问来源于stack exchange,提问作者Night Fury
相关产品推荐
相关产品推荐

