You need to enable JavaScript to run this app. discord.py cog内用监听器调用同cog任务函数的报错问题问询
优惠活动
大模型
产品
解决方案
定价
更多

discord.py cog内用监听器调用同cog任务函数的报错问题问询

问题排查与修复方案

各阶段报错的根因定位

  • 初始代码的「变量未定义」错误:Cog是基于类的扩展结构,所有内部方法、属性都属于类实例成员,必须通过self.前缀访问。直接在监听器里写repeater.start(),会在当前方法的局部作用域查找同名变量,找不到对应引用就会触发未定义异常。
  • 修改为self.repeater()后触发的Cog.listener类型错误:
  • 核心是混淆了「普通async函数」和「tasks.Loop实例」的逻辑边界。self.repeater不是可直接调用的普通函数,是被@tasks.loop装饰器包装生成的后台循环调度对象;
  • 这个报错的直接触发场景,通常是误将业务代码作为参数传入@commands.Cog.listener装饰器(比如错写为@commands.Cog.listener(self.repeater()))——该装饰器要求传入的参数是事件名字符串,收到函数类型的实参就会抛出类型校验失败。
  • 修改为await self.repeater()后循环只执行一次的问题:直接await循环调度对象,本质是执行它内部包裹的原始协程,完全绕过了tasks.Loop自带的间隔计时、后台调度、状态管理逻辑,自然无法实现每10秒重复运行的效果。

可正常运行的实现代码

修正两个核心逻辑:所有类内成员访问加self.前缀,启动循环任务必须调用循环对象自带的.start()方法。
完整代码如下:

import discord
from discord.ext import commands, tasks
    
class Repeater(commands.Cog):

    def __init__(self, client):
        self.client = client
    
    @tasks.loop(seconds=10)
    async def repeater(self):
        # 增加空值校验,避免频道未加载完成时发送消息报错
        channel = self.client.get_channel(834554679265329172)
        if channel:
            await channel.send('test')
    
    @commands.Cog.listener()
    async def on_ready(self):
        # 避免on_ready事件重复触发导致的任务重复启动
        if not self.repeater.is_running():
            self.repeater.start()
    
def setup(client):
    client.add_cog(Repeater(client))

优化提示

  • on_ready事件会在机器人网关重连、断线恢复时反复触发,必须搭配is_running()状态判断,否则会出现循环任务重复启动的报错。
  • 如果循环逻辑依赖机器人缓存的频道、成员数据,可以给repeater任务加前置等待逻辑,确保机器人完全加载后再启动循环:
@repeater.before_loop
async def before_repeater(self):
    await self.client.wait_until_ready()

内容的提问来源于stack exchange,提问作者Joseph Vandiver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 15:24:04