discord.py拆分代码至其他文件时出现NoneType无send属性报错
问题根因
核心错误是你在loging.py中重复实例化了一个全新的、未启动未登录的commands.Bot对象。这个独立创建的bot实例没有连接Discord网关,没有加载任何服务器、频道缓存,调用fetch_channel时根本拿不到对应频道对象,直接返回None,后续对None调用send方法就触发了报错。
- 主文件里的bot实例正常调用了
bot.run(TOKEN)完成登录,有完整的连接上下文,所以主文件中发消息逻辑正常 - 替换发送目标为
ctx.channel能正常运行,是因为ctx是从主文件正常运行的bot实例传递过来的,上下文自带的频道对象本身有效,不需要依赖loging.py里未登录的无效bot实例获取资源
修复方法
两种可行方案选其一即可,不要在拆分的功能模块里重复创建Bot实例,一个机器人进程只需要一个和Discord保持连接的Bot实例。
方法1:传递主bot实例到日志模块(改动最小)
删除loging.py里重复创建的bot实例,把主文件中已经登录运行的bot实例作为参数传入日志函数即可。
修改后的loging.py
import discord from datetime import datetime # 删除此处重复创建Bot实例的代码 # bot = commands.Bot(command_prefix=commands.when_mentioned_or("$"), help_command=None) async def comlog(ctx, bot): # 时间生成逻辑移到函数内部,避免全局变量固定为程序启动时间、不随调用更新 timenow = datetime.now().strftime(r"%x, %X") channelid = ctx.channel.id username = ctx.author usernameid = ctx.author.id # 用传入的、已正常登录的bot实例获取频道 logingchan = await bot.fetch_channel(983811124929630239) em = discord.Embed(title=f'${ctx.command}', description=f'{timenow}', color=0x00FF00) em.set_thumbnail(url=username.avatar_url) em.add_field(name="Channel:", value=f'{ctx.channel.mention} \n{channelid}', inline=True) em.add_field(name="User:", value=f'{username}\n{usernameid}', inline=True) print(f'{timenow}: ${ctx.command}: in "{ctx.channel}" by "{username}"') await logingchan.send(embed=em) await ctx.message.delete()
对应修改主文件bot.py的调用逻辑
@bot.command(name='test', help='this command will test') async def test(ctx): # 把当前正在运行的bot实例作为参数传入 await loging.comlog(ctx, bot)
方法2:使用Cog结构拆分功能(discord.py官方推荐模块化写法)
把日志功能封装为Cog挂载到主bot实例上,不需要手动传递实例,结构更清晰,适合功能较多的机器人项目。
修改后的loging.py
import discord from discord.ext import commands from datetime import datetime class LogCog(commands.Cog): def __init__(self, bot): self.bot = bot self.log_channel_id = 983811124929630239 async def comlog(self, ctx): timenow = datetime.now().strftime(r"%x, %X") logingchan = await self.bot.fetch_channel(self.log_channel_id) em = discord.Embed(title=f'${ctx.command}', description=f'{timenow}', color=0x00FF00) em.set_thumbnail(url=ctx.author.avatar_url) em.add_field(name="Channel:", value=f'{ctx.channel.mention} \n{ctx.channel.id}', inline=True) em.add_field(name="User:", value=f'{ctx.author}\n{ctx.author.id}', inline=True) print(f'{timenow}: ${ctx.command}: in "{ctx.channel}" by "{ctx.author}"') await logingchan.send(embed=em) await ctx.message.delete() # 提供给主bot加载Cog的入口 async def setup(bot): await bot.add_cog(LogCog(bot))
对应修改主文件bot.py的加载、调用逻辑
# 其余导入保持不变 import loging # bot实例化代码保持不变 bot = commands.Bot(command_prefix=commands.when_mentioned_or("$"), help_command=None) # 启动时加载日志Cog @bot.event async def on_ready(): await bot.load_extension("loging") print(f"Logged in as {bot.user}") @bot.command(name='test', help='this command will test') async def test(ctx): log_cog = bot.get_cog("LogCog") await log_cog.comlog(ctx) bot.run(TOKEN)
内容的提问来源于stack exchange,提问作者ΛSUKΛ
相关产品推荐
相关产品推荐

