简体   繁体   English

discord.py 中的异步竞争条件问题

[英]Async race condition problem in discord.py

I'm trying to make a simple command that allows a user to give themselves a role, but if the role doesn't exist, it will create the role first, then give them the role.我正在尝试制作一个简单的命令,允许用户给自己一个角色,但如果角色不存在,它将首先创建角色,然后给他们角色。 Here is my current code:这是我当前的代码:

@bot.command()
async def SetRole(ctx, arg):
    roles = ctx.guild.roles
    user = ctx.message.author

    #check if role does not exist
    if arg not in [role.name for role in roles]:
        await ctx.guild.create_role(name=arg)
    await user.add_roles(discord.utils.get(roles, name=arg))

The expected result when I run $SetRole test_role if test_role does not exist, would be that the bot creates the role and then gives me the role.如果 test_role 不存在,当我运行 $SetRole test_role 时的预期结果是机器人创建角色然后给我角色。 However, the role is created but is not given to me.但是,角色是创建的,但不是给我的。 Here is there error and stack trace:这里有错误和堆栈跟踪:

Ignoring exception in command SetRole:
Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "main.py", line 17, in SetRole
    await user.add_roles(discord.utils.get(roles, name=arg))
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/member.py", line 777, in add_roles
    await req(guild_id, user_id, role.id, reason=reason)
AttributeError: 'NoneType' object has no attribute 'id'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/ext/commands/core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'id'

If I run the command a second time, the role is successfully given to me.如果我再次运行该命令,则该角色已成功授予我。 What I presume is happening is for some reason, the user.add_roles() is happening before the create_role most likely because of some weirdness with async.我认为正在发生的事情是出于某种原因, user.add_roles()发生在create_role之前很可能是因为异步有些奇怪。 How can I make sure that it adds the role after its created?如何确保它在创建后添加角色?

This isn't a race condition, just that discord.py doesn't track and mutate objects everywhere这不是竞争条件,只是 discord.py 不会在任何地方跟踪和改变对象

A better implementation would be:更好的实现是:

from typing import Union

@bot.command()
async def SetRole(ctx, role: Union[Role, str]):
    if isinstance(role, str):
        role = await ctx.guild.create_role(name=role)
    await user.add_roles(role)

Union is just a way to represent "any of the given types", so discord.py [cleverly] either return a role or a string as fallback, we can then create the role if it doesn't already exist by checking if role is a string Union只是表示“任何给定类型”的一种方式,因此 discord.py [聪明地] 要么返回一个角色或一个字符串作为后备,然后我们可以通过检查role是否为字符串来创建角色如果它不存在

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM