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

discord.py开发机器人报NameError: name 'ws' is not defined求解

Discord.py 机器人 ?abc 指令触发 NameError 问题排查

问题背景

使用Python的discord.py库开发Discord对话机器人,引入asyncio、datetime、discord、openpyxl依赖,预期实现三个核心功能:

  • 机器人登录成功后输出状态提示、设置游玩状态
  • 接收?learn指令时,将用户输入的问答对写入memory.xlsx文件存储
  • 接收?abc指令时,从memory.xlsx中读取对应问题的答案发送到频道
    代码中已经编写ws = wb.active的工作表赋值逻辑,但运行时触发?abc指令直接抛出异常。

原代码与报错信息

问题代码

import asyncio
import datetime
import discord
import openpyxl

client = discord.Client(intents=discord.Intents.default())


@client.event
async def on_ready():
    print("접속완료했다용!"+ client.user.name)
    print(client.user.id)
    await client.change_presence(activity=discord.Game(name='디스코드봇 대화', type=1))



@client.event  
async def on_message(message):
   if message.content.startswith("?learn"):
    global ws
    word = message.content.split(" ")
    word_ = message.content.replace("?learn ", "").replace(word[1], "")
    wb = openpyxl.load_workbook("memory.xlsx")
    ws = wb.active
    
    

    for i in range(1, 10):           
        if ws["A" + str(i)].value == "." or None:
            ws["A" + str(i)].value = word[1]
            ws["B" + str(i)].value = word_
            await message.channel.send(ws["A1"].value)    
            break
    wb.save("memory.xlsx")

@client.event  
async def on_message(message):
if message.content.startswith("?abc"):
   global ws
   word = message.content.split(" ")
   wb = openpyxl.load_workbook("memory.xlsx")   
   ws = wb.active

for i in range(1, 10):
    if ws["A" + str(i)].value == word[1]:
        await message.channel.send(ws["B" + str(i)].value)
        break

报错栈

[30;1m2022-07-10 19:12:26[0m [31mERROR   [0m [35mdiscord.client[0m Ignoring exception in on_message
[31mTraceback (most recent call last):
File "C:\Users\준환\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 456, in _run_event
await coro(*args, **kwargs)
File "c:\Users\준환\Desktop\봇창고\학습\학습테스트.py", line 46, in on_message
if ws["A" + str(i)].value == word[1]:
NameError: name 'ws' is not defined[0m

报错产生原因

  1. 事件重复注册覆盖:discord.py框架下同类型事件如果重复定义,后注册的监听器会完全覆盖先注册的。代码中写了两个被@client.event装饰的on_message函数,第一个处理?learn指令的逻辑完全不会被执行。
  2. 缩进层级错误:第二个on_message函数内部代码缩进不符合Python语法规范,遍历Excel行匹配答案的for循环被写到了全局作用域,模块加载时就会执行,此时从未运行过ws变量的赋值逻辑,直接触发未定义错误。
  3. 判断逻辑错误:原代码中if ws["A" + str(i)].value == "." or None写法存在逻辑漏洞,该表达式恒为真,无法正确识别空单元格;同时写死遍历前10行的逻辑灵活性差,也没有处理指令参数缺失的边界场景。
  4. 全局变量滥用:将工作表对象ws声明为全局变量跨作用域访问,很容易出现变量未初始化就被调用的异常。

修复方案

按照以下规则调整代码即可解决问题:

  • 合并两个重复的on_message监听器到同一个函数内,避免事件覆盖
  • 统一修正代码缩进,确保所有指令判断、Excel读写逻辑都在对应作用域内
  • 修正空值判断逻辑,替换写死的行遍历范围为实际工作表最大行,增加参数合法性校验
  • 移除不必要的全局ws变量,每次操作Excel时在对应分支内完成加载、读写、关闭全流程,避免作用域异常
  • 增加忽略机器人自身消息的判断,避免机器人响应自己的消息触发死循环

修复后可运行的完整代码:

import asyncio
import datetime
import discord
import openpyxl

# 注意需要开启消息内容权限,否则无法读取用户发送的指令内容
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)

@client.event
async def on_ready():
    print("접속완료했다용!"+ client.user.name)
    print(client.user.id)
    await client.change_presence(activity=discord.Game(name='디스코드봇 대화', type=1))

@client.event  
async def on_message(message):
    # 忽略机器人自身发送的消息,避免死循环
    if message.author == client.user:
        return

    # 处理?learn学习指令
    if message.content.startswith("?learn"):
        # 拆分参数时限制拆分次数,避免回答内容包含空格被截断
        word = message.content.split(" ", 2)
        if len(word) < 3:
            await message.channel.send("사용법: ?learn [질문] [답변]")
            return
        question = word[1]
        answer = word[2]
        wb = openpyxl.load_workbook("memory.xlsx")
        ws = wb.active
        save_success = False

        # 遍历现有行查找空位置写入新问答
        for i in range(1, ws.max_row + 2):           
            cell_val = ws[f"A{i}"].value
            if cell_val == "." or cell_val is None:
                ws[f"A{i}"].value = question
                ws[f"B{i}"].value = answer
                save_success = True
                await message.channel.send(f"학습완료: {question} -> {answer}")    
                break
        if save_success:
            wb.save("memory.xlsx")
        wb.close()

    # 处理?abc查询指令
    if message.content.startswith("?abc"):
        word = message.content.split(" ", 1)
        if len(word) < 2:
            await message.channel.send("사용법: ?abc [질문]")
            return
        target_question = word[1]
        wb = openpyxl.load_workbook("memory.xlsx")   
        ws = wb.active
        find_success = False

        # 遍历行匹配问题
        for i in range(1, ws.max_row + 1):
            if ws[f"A{i}"].value == target_question:
                await message.channel.send(ws[f"B{i}"].value)
                find_success = True
                break
        if not find_success:
            await message.channel.send("해당 질문에 대한 답변을 찾지 못했습니다.")
        wb.close()

# 替换为你自己的机器人Token
client.run("YOUR_BOT_TOKEN")

注意:新版discord.py需要在开发者后台开启Message Content Intent,同时代码中配置对应intents,否则无法读取普通频道内的用户消息内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:18:03