在discord.py异步函数中使用外部变量的异常问题
Discord.py每日指令全局变量问题解决方案
问题描述
我正在开发一个discord.py机器人,想要创建/daily指令,但需要在异步函数内部使用外部声明的变量。当前代码如下:
global d d = 0 @tree.command(name = "daily", description = "Daily sallary.") async def daily(interaction: discord.Interaction): if d == 0: await interaction.response.send_message("Yes") d = 1 await asyncio.sleep(86400) d = 0 else: await interaction.response.send_message("No")
运行后抛出错误:
UnboundLocalError: cannot access local variable 'd' where it is not associated with a value
尝试修改为以下写法后:
global d d = 0 @tree.command(name = "daily", description = "Daily sallary.") async def daily(interaction: discord.Interaction, d=d): if d == 0: await interaction.response.send_message("Yes") d = 1 await asyncio.sleep(86400) d = 0 else: await interaction.response.send_message("No")
依旧报错:
TypeError: parameter 'd' is missing a type annotation in callback 'daily'
解决方法
1. 正确使用全局变量
第一个报错的核心原因是:在函数内部对全局变量d执行赋值操作时,Python会默认将其视为局部变量,但你在赋值前先引用了它,导致变量未绑定的错误。只需在函数内部再次声明global d,明确告知Python使用全局变量即可:
import discord from discord import app_commands import asyncio d = 0 # 全局变量无需在外部加global声明 @app_commands.command(name="daily", description="Daily salary.") async def daily(interaction: discord.Interaction): global d # 函数内部声明使用全局变量d if d == 0: await interaction.response.send_message("Yes") d = 1 # 注意:此处sleep会阻塞整个机器人进程,不推荐用于实际场景 await asyncio.sleep(86400) d = 0 else: await interaction.response.send_message("No")
2. 更合理的生产级方案(避免全局变量)
全局变量存在严重缺陷:所有用户共用同一个状态,一个用户领取后其他用户都无法使用,且asyncio.sleep会阻塞整个机器人,期间无法处理其他指令。建议用本地文件或数据库记录每个用户的最后领取时间:
import discord from discord import app_commands from datetime import datetime, timedelta import json # 用JSON文件存储用户领取记录 USER_DAILY_RECORD = "daily_records.json" def load_records(): try: with open(USER_DAILY_RECORD, "r") as f: return json.load(f) except FileNotFoundError: return {} def save_records(data): with open(USER_DAILY_RECORD, "w") as f: json.dump(data, f) @app_commands.command(name="daily", description="Daily salary.") async def daily(interaction: discord.Interaction): user_id = str(interaction.user.id) records = load_records() now = datetime.now() last_claim_time = records.get(user_id) if not last_claim_time or datetime.fromisoformat(last_claim_time) + timedelta(days=1) < now: await interaction.response.send_message("Yes,每日奖励领取成功!") records[user_id] = now.isoformat() save_records(records) else: next_available = datetime.fromisoformat(last_claim_time) + timedelta(days=1) await interaction.response.send_message(f"No,你需要等到{next_available.strftime('%Y-%m-%d %H:%M:%S')}才能再次领取!")
关于第二种写法的错误说明
你尝试给函数参数设置默认值d=d的方式不可行:Discord.py的指令函数参数只能对应指令的可选/必填参数,必须添加类型注解,这种写法会被框架识别为自定义指令参数,而非引用全局变量,因此会抛出类型注解缺失的错误。
内容的提问来源于stack exchange,提问作者TheLiveYT
相关产品推荐
相关产品推荐

