Python UnboundLocalError问题求助(Discord游戏工具开发)
问题:UnboundLocalError: cannot access local variable 'initial_data' where it is not associated with a value
开发本地Discord工具,从osu! API获取数据并存储为JSON,再通过Python函数将值存入元组,调用功能时触发上述错误。
报错栈信息
Traceback (most recent call last): File "/var/lib/pufferpanel/servers/bd502203/.local/lib/python3.11/site-packages/discord/app_commands/commands.py", line 862, in _do_call return await self._callback(interaction, **params) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/lib/pufferpanel/servers/bd502203/scoreposter.py", line 251, in scoreposter await interaction.response.send_message(f"```{scorepost(osu_user,mode , False)}```", ephemeral=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/lib/pufferpanel/servers/bd502203/scoreposter.py", line 168, in scorepost beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id = extract_initial_data(initial_data) ^^^^^^^^^^^^ UnboundLocalError: cannot access local variable 'initial_data' where it is not associated with a value The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/var/lib/pufferpanel/servers/bd502203/.local/lib/python3.11/site-packages/discord/app_commands/tree.py", line 1242, in _call await command._invoke_with_namespace(interaction, namespace) File "/var/lib/pufferpanel/servers/bd502203/.local/lib/python3.11/site-packages/discord/app_commands/commands.py", line 887, in _invoke_with_namespace return await self._do_call(interaction, transformed_values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/lib/pufferpanel/servers/bd502203/.local/lib/python3.11/site-packages/discord/app_commands/commands.py", line 880, in _do_call raise CommandInvokeError(self, e) from e discord.app_commands.errors.CommandInvokeError: Command 'scorepost' raised an exception: UnboundLocalError: cannot access local variable 'initial_data' where it is not associated with a value
相关代码片段
工具函数部分
def int_to_santised_int(value: int) -> int: if value == 0: return 0 else: mods_to_check = [1024, 512, 256, 64, 16, 8, 2] # FL, NC, HT, DT, HR, HD, EZ combined_value = 0 for mod in mods_to_check: if value & mod: combined_value |= mod return combined_value def extract_initial_data(initial_data): try: beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id = ( initial_data[0]["beatmap_id"], initial_data[0]["rank"], int(initial_data[0]["maxcombo"]), int(initial_data[0]["count300"]), int(initial_data[0]["count100"]), int(initial_data[0]["count50"]), int(initial_data[0]["countmiss"]), initial_data[0]["perfect"], int_to_santised_int(int(initial_data[0]["enabled_mods"])), initial_data[0]["score_id"] ) except IndexError as e: print(f"an exception occurred: '{e}'; that user probably doesn't have any data available.") raise return beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id
核心功能函数
def scorepost(username : str, link : bool, mode : str): # make a request to the osu! API to retrieve the user's most recent play if link == False: try: print(f"making initial score request for {username}...") inital_response_user = requests.get(f"https://osu.ppy.sh/api/get_user_recent?k={osu_api_key}&u={username}&m={gamemode}&limit=1") print(inital_response_user) except: return "No plays done by that player recently" else: # parse the response as JSON initial_data = inital_response_user.json() beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id = extract_initial_data(initial_data)
解决方案
核心问题分析
- 参数顺序不匹配:调用
scorepost时的参数顺序与函数定义不一致,导致link参数未接收到预期的False值,无法进入API请求逻辑,initial_data未被定义。 - 分支覆盖不全:当
link != False时,没有为initial_data赋值的逻辑,直接调用extract_initial_data必然触发未定义错误。 - 拼写错误隐患:
inital_response_user存在拼写错误(应为initial_response_user),虽当前不影响运行,但易引发后续维护问题。
修复步骤
修正参数调用顺序
原调用代码将mode和False的顺序传反,需调整为函数定义的username, link, mode顺序:# 原调用 # await interaction.response.send_message(f"```{scorepost(osu_user,mode , False)}```", ephemeral=False) # 修改后 await interaction.response.send_message(f"```{scorepost(osu_user, False, mode)}```", ephemeral=False)完善分支逻辑,确保
initial_data始终被定义
在函数开头初始化initial_data为默认值,并补充link == True时的处理逻辑,避免未定义:def scorepost(username : str, link : bool, mode : str): initial_data = [] # 初始化默认值 if link == False: try: print(f"making initial score request for {username}...") # 修正拼写错误 initial_response_user = requests.get(f"https://osu.ppy.sh/api/get_user_recent?k={osu_api_key}&u={username}&m={gamemode}&limit=1") print(initial_response_user) except Exception as e: print(f"API请求失败: {str(e)}") return "No plays done by that player recently" else: initial_data = initial_response_user.json() else: # 补充link为True时的数据获取逻辑,例如从链接解析数据 # 示例:initial_data = parse_link_data(link) pass # 调用前检查数据有效性 if not initial_data: return "No valid play data found" beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id = extract_initial_data(initial_data) # 后续业务逻辑...修正拼写错误
将inital_response_user统一改为initial_response_user,保持变量名拼写一致,降低维护风险。增强异常处理
在extract_initial_data中添加空数据检查和KeyError捕获,提前处理无效数据:def extract_initial_data(initial_data): if not initial_data: raise ValueError("No play data available") try: beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id = ( initial_data[0]["beatmap_id"], initial_data[0]["rank"], int(initial_data[0]["maxcombo"]), int(initial_data[0]["count300"]), int(initial_data[0]["count100"]), int(initial_data[0]["count50"]), int(initial_data[0]["countmiss"]), initial_data[0]["perfect"], int_to_santised_int(int(initial_data[0]["enabled_mods"])), initial_data[0]["score_id"] ) except IndexError as e: print(f"an exception occurred: '{e}'; that user probably doesn't have any data available.") raise except KeyError as e: print(f"Missing expected data field: {e}") raise return beatmap_id, rank, score_max, n300, n100, n50, nmiss, perfect, int_mods, score_id
内容的提问来源于stack exchange,提问作者rOxANDtOl
相关产品推荐
相关产品推荐

