discord.py如何在Cog初始化时调用async异步函数
问题核心原因
- 直接将
__init__声明为异步方法:Python的类构造函数要求为同步方法,必须返回None,异步方法调用后会返回协程对象,不符合构造函数的调用要求,直接触发TypeError。 - 自行新建事件循环执行异步初始化:新建的事件循环和bot运行的主事件循环完全隔离,状态不共享;且Cog加载阶段bot还未完成和Discord网关的连接,
guilds列表尚未加载,自然查不到对应服务器,返回None。
最优实现方案
discord.py官方提供了Cog生命周期钩子async def cog_load(self),该方法会在Cog被加载到bot时自动在bot的主事件循环中异步执行,完全满足初始化阶段运行异步逻辑的需求。
完整foo.py实现
import discord from discord.ext import commands # 用常量存储固定ID,无需使用全局变量 GUILD_ID = 替换为你的服务器ID SPECIAL_ROLE_ID = 替换为你的特殊角色ID class Variables(commands.Cog): def __init__(self, bot): self.bot = bot # 同步初始化仅赋值实例属性,异步逻辑全部放到cog_load中 self.guild = None self.special_role = None async def cog_load(self): # Cog加载完成后自动异步执行该方法 print('Cog异步初始化开始') # 查找目标服务器 self.guild = discord.utils.get(self.bot.guilds, id=GUILD_ID) if not self.guild: print(f'未找到ID为{GUILD_ID}的服务器,请检查ID配置') return # 查找目标角色 self.special_role = discord.utils.get(self.guild.roles, id=SPECIAL_ROLE_ID) # 异步操作可直接在该方法中执行 await self.bot.change_presence(activity=discord.Streaming( name='Author: Author', url='https://www.youtube.com/watch?v=dQw4w9WgXcQ' )) print('Cog异步初始化完成') @commands.command() async def test(self, ctx): await ctx.send(f'当前绑定服务器:{self.guild}') if self.special_role: await ctx.send(f'特殊角色:{self.special_role.mention}') # discord.py 2.0+版本支持异步setup,兼容性更好 async def setup(bot): await bot.add_cog(Variables(bot))
旧版本兼容方案
如果使用不支持cog_load的低版本discord.py,可在__init__中通过bot的主事件循环提交异步任务,同时添加等待逻辑确保bot登录完成:
def __init__(self, bot): self.bot = bot # 直接用bot的主事件循环提交异步任务,无需新建循环 self.bot.loop.create_task(self._async_init()) async def _async_init(self): # 等待bot完成登录,确保guilds列表加载完毕 await self.bot.wait_until_ready() # 后续异步初始化逻辑和上面cog_load中的逻辑一致
你最后修改的main.py逻辑是正确的,将Cog加载放到on_ready中执行,保证触发初始化时bot已经完成网关连接,服务器数据已经加载完毕。
内容的提问来源于stack exchange,提问作者omar
相关产品推荐
相关产品推荐

