discord.py机器人报UnboundLocalError:levelup变量赋值前被引用
问题复现代码
起始代码
with open('data/level','r') as file: to_level = file.readline() client = commands.Bot(command_prefix=".")
触发报错的函数代码(第44行为if levelup == 81:)
@client.event async def on_message(message): channel = client.get_channel(int(spam_id)) if message.channel.id == int(spam_id): if message.author.id == poketwo: if message.embeds: embed_content = message.embeds[0].description if 'now level' in embed_content: split = embed_content.split(' ') a = embed_content.count(' ') levelup = int(split[a].replace('!', '')) if levelup == 81: spam.cancel() await channel.send(f".s {to_level}") spam.start() with open('data/level', 'r') as fi: data = fi.read().splitlines(True) with open('data/level', 'w') as fo: fo.writelines(data[1:]) await client.process_commands(message)
抛出的错误信息
Ignoring exception in on_message Traceback (most recent call last): File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 301, in _run_event await coro(*args, **kwargs) File "main.py", line 44, in on_message if levelup == 81: UnboundLocalError: local variable 'levelup' referenced before assignment
错误产生原因
- Python函数内的局部变量必须先完成赋值才能被访问。
levelup的赋值逻辑被嵌套在4层if判断内部,只有所有判断条件全部命中(消息来自指定spam频道、发送者是poketwo账号、消息携带embed、embed描述包含now level字段)时,才会给levelup赋值。只要任意一个条件不满足,levelup变量就不会被创建,后续代码直接读取该变量就会触发「赋值前引用局部变量」的错误。 - 代码还存在缩进错误:读取文件内容的
data = fi.read().splitlines(True)没有缩进在with open('data/level', 'r') as fi:的代码块范围内,就算前面的等级判断正常执行,到文件操作步骤也会抛出IO相关错误。
修复方法
- 在
on_message函数的开头位置给levelup设置默认初始值,比如levelup = 0,保证不管走哪个分支逻辑,这个变量都已经被定义,不会出现未创建就访问的问题。 - 修正文件读取部分的缩进错误,把
data = fi.read().splitlines(True)缩进到对应的with代码块内,保证文件句柄处于打开状态时执行读取操作。 - 可选优化:把
if levelup == 81的判断逻辑挪到外层频道判断的内部,非指定频道的消息不需要走等级判断逻辑,减少无意义的性能消耗。
修复后的完整代码
with open('data/level','r') as file: to_level = file.readline() client = commands.Bot(command_prefix=".") @client.event async def on_message(message): levelup = 0 # 初始化变量解决未赋值引用问题 channel = client.get_channel(int(spam_id)) if message.channel.id == int(spam_id): if message.author.id == poketwo: if message.embeds: embed_content = message.embeds[0].description if 'now level' in embed_content: split = embed_content.split(' ') a = embed_content.count(' ') levelup = int(split[a].replace('!', '')) # 等级判断移入频道判断分支,减少无效判断 if levelup == 81: spam.cancel() await channel.send(f".s {to_level}") spam.start() with open('data/level', 'r') as fi: # 修正缩进,在with块内读取文件 data = fi.read().splitlines(True) with open('data/level', 'w') as fo: fo.writelines(data[1:]) await client.process_commands(message)
内容的提问来源于stack exchange,提问作者Bhavy Upreti
相关产品推荐
相关产品推荐

