如何在discordpy机器人中实现可执行异步代码的/run指令?
报错根源
你遇到的SyntaxError: 'await' outside function本质是exec()默认将传入代码作为模块级同步代码块执行,Python语法规定await关键字只能存在于async修饰的协程函数内部,模块级顶层代码无法直接使用await,自然触发语法错误。
实现方案
核心解决思路是将用户传入的带await的代码,包装到自定义的临时异步协程函数内部,再手动驱动协程运行,即可完全规避await的作用域限制,匹配预期交互效果。
可直接复用的代码示例:
from discord.ext import commands import discord # 按需求开启对应intents intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix="!", intents=intents) @bot.slash_command(name="run", description="执行传入的Python代码") async def run_code(ctx: commands.Context, code: str): # 自动清洗用户传入的代码,兼容markdown代码块格式 code = code.replace("```py", "").replace("```", "").strip() # 把用户传入的所有代码包装成异步函数,满足await的语法作用域要求 wrapped_code = f""" async def __eval_coro(): {code} """ # 准备执行作用域,提前暴露常用对象给用户代码 global_scope = { "bot": bot, "ctx": ctx, "discord": discord, "commands": commands } local_scope = {} try: exec(wrapped_code, global_scope, local_scope) # 拿到临时生成的协程函数直接执行 coro = local_scope["__eval_coro"] await coro() except Exception as e: # 捕获执行异常,将错误信息反馈给调用者 await ctx.respond(f"代码执行报错:{type(e).__name__}: {str(e)}", ephemeral=True)
执行逻辑验证:当用户输入指令/run code: await ctx.send("hi stackoverflow"),机器人会直接返回hi stackoverflow,和预期效果完全一致。该方案同时兼容多行代码执行,不会限制用户仅输入单行内容。
关键注意事项
- 极高的安全风险:该指令相当于将bot进程的完整执行权限开放给调用者,无限制开放会让恶意用户随意篡改bot所在服务器、窃取bot权限下的所有数据,甚至在运行bot的主机上执行恶意代码。必须添加严格的权限校验,仅允许bot所有者调用该指令,示例校验逻辑:
# 加在run指令函数的最开头 if not await bot.is_owner(ctx.author): await ctx.respond("无指令调用权限", ephemeral=True) return - 后续可扩展支持自动捕获代码返回值:比如用户写
return "执行成功",自动将返回内容作为消息发送,减少用户重复写ctx.send的冗余代码 - 如果需要支持更复杂的调试场景,可以在执行作用域内置入常用的第三方库对象,减少用户重复import的操作
内容的提问来源于stack exchange,提问作者BlackHummingbird
相关产品推荐
相关产品推荐

