如何将discord.py的事件处理代码拆分到独立文件中
Discord.py 日志功能模块化实现方案
discord.py 原生提供了 Cog 机制专门做功能拆分,不需要自己手写复杂的导入绑定逻辑,是目前最稳妥的模块化方案,拆分后主文件只需要保留启动逻辑,所有日志相关的事件处理都可以独立到单独文件里。
第一步:调整目录结构
先把文件按功能拆分,推荐结构如下:
your_bot/ ├── main.py # 机器人启动入口 ├── cogs/ # 所有模块化功能存放目录 │ ├── __init__.py # 空文件即可,标记为Python包 │ └── log_event.py # 所有日志相关事件处理放这里 └── utils/ └── log_util.py # 你原来写的Logging工具类移到这里
第二步:编写日志模块Cog
把你原来写的所有事件监听代码移到cogs/log_event.py里,替换成Cog写法:
from discord.ext import commands import discord from utils.log_util import Logging class LogCog(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot # 全局复用一个Logging实例,不要每次触发事件都新建 self.logger = Logging() # 用Cog自带的监听器装饰器代替原来的@bot.event @commands.Cog.listener() async def on_message_delete(self, m): # 过滤机器人自身消息,避免无效日志 if m.author.bot: return created_at = m.created_at.strftime('%d-%m-%Y %H:%M:%S') log_content = f'{m.author} deleted message.\n[{created_at}] "{m.content}"' await self.logger.write_log(1, log_content) @commands.Cog.listener() async def on_message_edit(self, m_before, m_after): if m_after.author.bot: return # 过滤内容没变化的编辑事件(比如嵌入卡片加载触发的自动edit) if m_before.content == m_after.content: return created_at = m_after.created_at.strftime('%d-%m-%Y %H:%M:%S') edited_at = m_after.edited_at.strftime('%d-%m-%Y %H:%M:%S') log_content = f'{m_after.author} edited message.\n[{created_at}] "{m_before.content}"\n[{edited_at}] "{m_after.content}"' await self.logger.write_log(1, log_content) @commands.Cog.listener() async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): if payload.member.bot: return channel = self.bot.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) created_at = message.created_at.strftime('%d-%m-%Y %H:%M:%S') # 修正原代码里addded的拼写错误 log_content = f'{payload.member} added reaction {payload.emoji} to message from {message.author}.\n[{created_at}] "{message.content}"' await self.logger.write_log(2, log_content) @commands.Cog.listener() async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): channel = self.bot.get_channel(payload.channel_id) message = await channel.fetch_message(payload.message_id) # 原代码这里有bug:raw移除反应事件的payload不带member属性,要自己通过user_id查 user = self.bot.get_user(payload.user_id) created_at = message.created_at.strftime('%d-%m-%Y %H:%M:%S') log_content = f'{user} removed reaction {payload.emoji} from message by {message.author}.\n[{created_at}] "{message.content}"' await self.logger.write_log(2, log_content) # Cog固定加载入口,主文件直接调用即可 async def setup(bot: commands.Bot): await bot.add_cog(LogCog(bot))
第三步:修改主启动文件
原来主文件里堆的所有日志相关事件代码全删掉,只保留启动和加载Cog的逻辑即可:
import discord from discord.ext import commands import os from dotenv import load_dotenv load_dotenv() # 记得开启对应权限的intents,否则事件无法触发 intents = discord.Intents.default() intents.message_content = True intents.reactions = True bot = commands.Bot(command_prefix='!', intents=intents) # 启动钩子中加载日志模块 @bot.event async def setup_hook(): await bot.load_extension('cogs.log_event') print("日志模块加载完成") bot.run(os.getenv('BOT_TOKEN'))
补充说明
- 后续要加新的日志事件,直接在
LogCog类里新增对应监听函数即可,不需要修改主文件 - 其他功能(比如审核、娱乐命令、定时任务)都可以按同样的逻辑拆成独立Cog文件,互相完全不耦合
- 如果你不想用Cog,也可以手动在单独的events文件里写接收bot参数的注册函数,内部用
@bot.event绑定事件,但这种方式后续扩展命令、做权限控制都很麻烦,不推荐 - 注意要在Discord开发者后台对应机器人的页面开启Message Content Intent等开关,否则部分事件不会推送
内容的提问来源于stack exchange,提问作者wracker
相关产品推荐
相关产品推荐

