You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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Λ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:45:49