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

Discord Bot中client.loop.create_task调用报错的技术问询

问题:Discord Bot调用client.loop.create_task触发AttributeError

搭建Discord Bot时,编写了update_stats函数用于统计服务器消息数、新成员数并写入stats.txt,但调用client.loop.create_task(update_stats())时出现以下错误:

File "C:\Users\.vscode\repo\discord bot\bot2", line 84, in <module>
    client.loop.create_task(update_stats())
    ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: loop attribute cannot be accessed in non-async contexts. Consider using either an asynchronous main function and passing it to asyncio.run or using asynchronous initialisation hooks such as Client.setup_hook

原因

discord.py v2.0+版本移除了在非异步上下文直接访问client.loop的支持,必须通过异步初始化钩子或异步主函数来创建后台任务。

解决方案

方法1:使用setup_hook异步钩子

在client实例化后,添加setup_hook函数注册后台任务:

client = discord.Client(intents=intents)

async def setup_hook():
    client.loop.create_task(update_stats())

client.setup_hook = setup_hook

方法2:使用异步主函数

将Bot启动逻辑放入异步主函数,通过asyncio.run执行:

async def main():
    async with client:
        client.loop.create_task(update_stats())
        await client.start(TOKEN)

asyncio.run(main())

(注意:此方式需删除原代码末尾的client.run(TOKEN)和client.loop.create_task(update_stats()))

代码其他问题修正

除上述报错外,代码还有几处逻辑/语法错误需要修正:

  1. on_member_join模块:

    • member.server改为member.guild(discord.py v1.5+已弃用server属性)
    • joined += joined改为joined += 1(原逻辑会让数值翻倍,统计错误)
    • str(channel) == ['general', 'welcome']改为channel.name in ['general', 'welcome'](原逻辑是字符串与列表比较,永远为False)
    • 移除过时的client.send_message,改为await channel.send(...)
  2. ID类型问题:

    • client.get_guild("client id")改为client.get_guild(123456789)(服务器ID必须是整数,不能是字符串)
    • await client.fetch_channel("")填入正确的整数频道ID,比如await client.fetch_channel(987654321)
  3. 权限补充:

    • 开启成员意图:intents.members = True,否则无法触发on_member_join事件

修正后的完整代码示例

import os
import time
import asyncio
import discord
from discord import app_commands
from discord.ui import button, view
from discord.ext import commands, tasks

# 替换为实际的Token和服务器信息
TOKEN = 'your_bot_token'
GUILD = "your_guild_name"
CHANNEL_ID = 123456789  # 欢迎频道ID
GUILD_ID = 987654321    # 服务器ID

messages = joined = 0
intents = discord.Intents.default()
intents.message_content = True
intents.members = True  # 开启成员意图
client = discord.Client(intents=intents)

async def update_stats():
    await client.wait_until_ready()
    global messages, joined

    while not client.is_closed():
        try:
            with open("stats.txt", "a") as f:
                f.write(f"Time : {int(time.time())}, Messages : {messages}, Members Joined : {joined}\n")

            messages = 0
            joined = 0

            await asyncio.sleep(5)

        except Exception as e:
            print(e)
            await asyncio.sleep(5)

# 注册后台任务
async def setup_hook():
    client.loop.create_task(update_stats())

client.setup_hook = setup_hook

@tasks.loop(seconds=5)
async def auto_send(channel : discord.TextChannel):
    await channel.send("Welcome")

@client.event
async def on_ready():
    if not auto_send.is_running():
        channel = await client.fetch_channel(CHANNEL_ID)
        auto_send.start(channel)
    
    guild = discord.utils.get(client.guilds, name=GUILD)
    if guild:
        print(
            f'{client.user} 已成功连接到服务器:\n'
            f'{guild.name}(id: {guild.id})'
        )
    
    await client.change_presence(
        activity=discord.Activity(name='anything', type=discord.ActivityType.playing)
    )

@client.event
async def on_member_join(member):
    global joined
    joined += 1
    for channel in member.guild.channels:
        if channel.name in ['general', 'welcome']:
            await channel.send(f"Welcome to the server! {member.mention}")

@client.event
async def on_message(message):
    global messages
    messages += 1
    
    guild = client.get_guild(GUILD_ID)
    channels = ["welcome", "mods" ,"general", "bot-commands", "admins"]
    valid_users = ["your_username"]  # 替换为实际用户名

    if str(message.channel) in channels and str(message.author) in valid_users :        
        print(message.content)
        if message.content.find("!hello") != -1:
            await message.channel.send("Hi")
        elif message.content == '!users' and guild:
            await message.channel.send(f"成员数量 : {guild.member_count}")
        else:
            print(f"用户 : {message.author} 尝试在 #{message.channel} 频道执行命令 {message.content}!")

client.run(TOKEN)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:36:18