【问题标题】:Async function as Decorator on Discord.pyDiscord.py 上作为装饰器的异步功能
【发布时间】:2021-10-19 22:18:44
【问题描述】:

我有一个 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))

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

【问题讨论】:

    标签: python discord.py python-decorators


    【解决方案1】:

    你不需要让最外层的函数异步,但是predicate函数可以是协程

    def custom_permission(permission):
        async def predicate(ctx):
            ...
        return commands.check(predicate)
    

    请记住,predicate 协程只能接受一个参数,ctx(参数在 commands.check 方法内部传递,你自己传递它们)如果你想要访问其他参数使用ctx.args

    【讨论】:

    • 当 args 在 custom_permission 装饰器中时,我能在 ctx.args 中得到它吗?
    • 您仍然可以使用permission 参数。通过“访问其他参数使用ctx.args”我的意思是实际命令参数。
    【解决方案2】:
    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.partialpredicate 函数部分应用于permissions 参数:

    async def _check_permission(ctx, permission):
        ...
    
    def custom_permission(permission):
    
        return commands.check(partial(_check_permission, permission=permission))
    

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

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

    【讨论】:

    • 你愿意聊天吗?我的 Discord 是 Benitz Original#1317
    猜你喜欢
    • 2018-05-10
    • 2021-06-15
    • 2021-07-10
    • 2022-01-09
    • 2021-12-29
    • 2011-02-14
    • 1970-01-01
    • 2018-04-11
    • 2012-01-26
    相关资源
    最近更新 更多