首页 > 解决方案 > Discord.py 上作为装饰器的异步功能

问题描述

我有一个 Discord.py 命令,我想制作一个自定义权限处理程序。

我的命令:

@commands.command()
@custom_permission("administrator")
async def example(self, ctx, args):
    ...

在这种情况下,@custom_permission()是 Permission 处理程序,现在我如何使它适用于 async def 中的装饰器?

装饰器功能:

async def custom_permission(permission):
    
    async def predicate(ctx, permission):
        if ctx.author.id in config.owners:
            return True

        elif permission == "administrator":
            if ctx.author.guild_permissions.administrator:
                return True

            else:
                embed = discord.Embed(timestamp=ctx.message.created_at, description=f"You do not meet the required guild permissions the command \"`{ctx.command.name}`\" requires to be executed.\n\nYou need `{permission.upper()}` Permission in this Guild to be able to execute/run/use this command.", color=242424)
                embed.set_author(name="Insufficient Permissions", icon_url=config.forbidden_img)
                embed.set_footer(text="Numix", icon_url=config.logo)
                await ctx.send(embed=embed)

        elif permission == "manage_messages":
            if ctx.author.guild_permissions.manage_messages:
                return True

            else:
                embed = discord.Embed(timestamp=ctx.message.created_at, description=f"You do not meet the required guild permissions the command \"`{ctx.command.name}`\" requires to be executed.\n\nYou need `{permission.upper()}` Permission in this Guild to be able to execute/run/use this command.", color=242424)
                embed.set_author(name="Insufficient Permissions", icon_url=config.forbidden_img)
                embed.set_footer(text="Numix", icon_url=config.logo)
                await ctx.send(embed=embed)

        elif permission == "kick":
            if ctx.author.guild_permissions.kick:
                return True

            else:
                embed = discord.Embed(timestamp=ctx.message.created_at, description=f"You do not meet the required guild permissions the command \"`{ctx.command.name}`\" requires to be executed.\n\nYou need `{permission.upper()}` Permission in this Guild to be able to execute/run/use this command.", color=242424)
                embed.set_author(name="Insufficient Permissions", icon_url=config.forbidden_img)
                embed.set_footer(text="Numix", icon_url=config.logo)
                await ctx.send(embed=embed)

        elif permission == "ban":
            if ctx.author.guild_permissions.ban:
                return True
                
            else:
                embed = discord.Embed(timestamp=ctx.message.created_at, description=f"You do not meet the required guild permissions the command \"`{ctx.command.name}`\" requires to be executed.\n\nYou need `{permission.upper()}` Permission in this Guild to be able to execute/run/use this command.", color=242424)
                embed.set_author(name="Insufficient Permissions", icon_url=config.forbidden_img)
                embed.set_footer(text="Numix", icon_url=config.logo)
                await ctx.send(embed=embed)

        elif permission == "manage_guild":
            if ctx.author.guild_permissions.manage_guild:
                return True

            else:
                embed = discord.Embed(timestamp=ctx.message.created_at, description=f"You do not meet the required guild permissions the command \"`{ctx.command.name}`\" requires to be executed.\n\nYou need `{permission.upper()}` Permission in this Guild to be able to execute/run/use this command.", color=242424)
                embed.set_author(name="Insufficient Permissions", icon_url=config.forbidden_img)
                embed.set_footer(text="Numix", icon_url=config.logo)
                await ctx.send(embed=embed)
        

    return commands.check(predicate(ctx, permission))

现在,我该如何进行这项工作?我无法将其更改为正常功能,因为如果我这样做了,那么当满足权限要求时,我将无法发送嵌入消息。

标签: pythondiscord.pypython-decorators

解决方案


  1. 装饰器语法:
@decorator
def function():
    ...

只是语法糖:

def function():
    ...
function = decorator(function)
  1. 异步函数是返回协程的函数。

In [1]: async def foo():
   ...:     return 42
   ...: 

In [2]: await foo()
Out[2]: 42

In [3]: foo()
Out[3]: <coroutine object foo at 0x7f7ca626da40>

所以当你这样做时

@an_async_function("argument")
async def foo():
    ...

an_async_function("argument")将是您尝试调用的协程对象。

  1. commands.check需要一个异步函数,而您正在传递对该函数的调用。

你可以做的是:

a)functools.partial用于将predicate函数部分应用于permissions参数:

async def _check_permission(ctx, permission):
    ...

def custom_permission(permission):

    return commands.check(partial(_check_permission, permission=permission))

b)只需使用permission您在装饰器内部传递的predicate

def custom_permission(permission):
    
    async def predicate(ctx):
        ...  # use `permission` here

    return commands.check(predicate)

推荐阅读