Python 如何将命令协程保存在可以通过另一个命令访问的变量中?
我试图在discord bot中实现的是一个系统,该系统在同一用户调用另一个命令时立即停止正在运行的命令协同路由,试图为每个用户保留一个唯一的活动会话 所以本质上,我需要能够访问该协程对象,并从另一个协程中阻止它 到目前为止,我所尝试的方法在我看来是合乎逻辑的,但我确信对于discordapi如何处理协同路由存在一些误解。以下是一个基本示例:Python 如何将命令协程保存在可以通过另一个命令访问的变量中?,python,discord,discord.py,coroutine,Python,Discord,Discord.py,Coroutine,我试图在discord bot中实现的是一个系统,该系统在同一用户调用另一个命令时立即停止正在运行的命令协同路由,试图为每个用户保留一个唯一的活动会话 所以本质上,我需要能够访问该协程对象,并从另一个协程中阻止它 到目前为止,我所尝试的方法在我看来是合乎逻辑的,但我确信对于discordapi如何处理协同路由存在一些误解。以下是一个基本示例: active_sessions = {} @bot.command() async def first_command(ctx): # Sav
active_sessions = {}
@bot.command()
async def first_command(ctx):
# Saving the coroutine in the dictionary with the user ID as key:
active_sessions[ctx.author.id] = ctx.command.callback
# do stuff
@bot.command()
async def second_command(ctx):
# Accessing the coroutine object and trying to stop it.
try:
coro = active_sessions[ctx.author.id]
coro.close()
except KeyError:
pass
它抛出一个AttributeError
声明函数对象没有属性close。
但是,根据discord.py docs,command.callback
指的是应该具有close方法的协同程序对象。还尝试了coro.cancel()
,结果相同
我在概念上做了一些错误的事情,但我不确定到底是什么,而且我也不知道如何正确地实施我的想法,所以非常感谢任何帮助
编辑
所以,由于我的目标可能还不清楚,以下是我试图实现的目标
我在做一个有点像游戏的不和谐机器人。用户可以运行多个命令,其中许多命令会等待一定时间,等待命令作者的反应或消息
但是这个用户可能会在没有“完成”第一个命令的情况下运行另一个命令,如果他们返回到第一个命令,他们的反应仍然会被接受
我试图避免这种行为,让用户专注于“单一会话”;无论运行什么命令,都需要自动停止前一个命令的执行
所以我是如何实现这一点的,这源于对协同程序的错误误解,就是拥有一个字典,将每个用户与当前正在运行的命令的循环相关联。如果另一个循环开始时另一个循环仍在运行,“旧循环”将停止,字典中的相应条目将用新循环更新:
active_sessions = {}
@bot.command()
async def first_command(ctx):
# In this first command I want to assign the current loop to a variable and
# add it to the active_sessions dictionary along with the ID of the command author.
# Then there's a loop that waits for user's reaction.
# Ignore the details such as the check function.
while True:
try:
reaction, user = await bot.wait_for("reaction_add",timeout=60,check=check)
# some if conditions here make the bot behave differently according
# to the specific reaction added
except asyncio.TimeoutError:
return
@bot.command()
async def second_command(ctx):
# As soon as this second command is invoked, I need to access the 'loop object'
# previously stored in the dictionary (if any) and stop it from here.
有两种方法可以实际停止
wait_for
的工作
导入json
@bot.event()
反应添加时的异步定义(反应,用户):
#使用配置变量
将open('config.json','r')作为f:
data=json.load(f)
如果数据[‘等待反应’]:
#在这里做事
其他:
返回
@commands.command()
异步def激活(ctx):
#激活监听器
将open('config.json','r')作为f:
data=json.load(f)
数据['wait_for_reaction']=True
将open('config.json','w')作为f:
write(数据,f,缩进=4)
等待ctx.send('activated listener')
@commands.command()
异步def停用(ctx):
将open('config.json','r')作为f:
data=json.load(f)
数据['wait_for_reaction']=False
将open('config.json','w')作为f:
write(数据,f,缩进=4)
等待ctx.send('activated listener')
您还可以使用全局变量或.env
文件来加载配置变量
来自discord.ext导入任务
@tasks.loop(秒=0)
异步定义任务(ctx):
尝试:
反应,用户=等待机器人。等待(“反应添加”,超时=60,检查=检查)
除asyncio.TimeoutError外:
返回
@commands.command():
异步def激活(ctx):
尝试:
任务启动(ctx)
除运行时错误外:
等待ctx.send(“任务已在运行”)
最后:
等待ctx.send('已启动任务')
@commands.command()
异步def停用(ctx):
任务停止()
等待ctx.send('已停止任务')
问题是,任务一次只能运行一个任务,因此不能在多个上下文中使用该命令。有一个解决方法,但我不建议使用它。仅当您的机器人是仅由您运行的个人机器人时才使用任务
参考资料:
如果要使用
.env
文件存储变量。看看你到底想用什么来实现目标<代码>coro.取消?ctx.command.callback
返回一个协同程序,而不是一个可以取消的正在运行的循环。谢谢您的评论。是的,我肯定我指的是错误的物体。如果可能的话,我如何从另一个循环管理一个特定的循环呢?当然可以。但你应该弄清楚,你想阻止或控制什么?你目前的方法肯定行不通。更多关于你正在尝试做的事情的见解将有助于轻松获得答案。使用更多信息编辑。非常感谢你的答案。我发现第一种方法非常有趣。问题是我可能需要为一个命令启用on_反应侦听器,而为另一个命令禁用on_反应侦听器,因此我无法使用布尔标志管理它。