猿问

如何扩展 client.command 的功能?

我正在尝试添加对client.command(client作为discord.ext.commands.Bot实例)的错误、args、kwargs 和函数内容的处理。基本上,我试图让我的所有命令具有某些共同的自定义行为。


我最初的想法是创建一个返回装饰器的函数,该装饰器用client.command.


但是,我遇到的最大问题是,返回的装饰器的参数处理client.command(...)完全取决于被装饰函数的参数和注解的排列方式,也就是说,像这样带有参数的包装器


async def wrapper(*args, **kwargs):

将收到原始参数。这意味着我必须自己处理包装器内的所有内容,这discord.ext.commands首先破坏了使用的全部意义。


阅读PEP 3107,我试图想出一个解决方法。这是代码的草图,与问题无关的部分被删掉了:


from discord.ext import commands as c

import discord as d

client = c.Bot(command_prefix = "insert_prefix_here$")




def command(*args, **kwargs):

    def decorator(func):

        command_name = kwargs.setdefault("name", func.__name__)


        async def wrapper(ctx, *args, **kwargs):

            # do stuff with func and command_name


        # ...eh? this down here is the dirtiest thing i've ever seen

        wrapper.__defaults__ = func.__defaults__

        wrapper.__annotations__ = func.__annotations__


        wrapper = client.command(*args, **kwargs)(wrapper)



        @wrapper.error

        async def wrapper_error(ctx, error):

            # do stuff with ctx, error, command_name, ... etc


        return wrapper


    return decorator


# insert commands with @command(...) decorator here

我短暂地想到了“欺骗”返回的装饰器,client.command(...)认为包装器的参数结构与装饰函数的参数结构相同,方法是将包装器__default__和__annotations__属性设置为装饰函数的参数结构。


是的,我完全意识到这是一个可怕的、没有经过深思熟虑的想法(它甚至行不通)。这就是为什么我发布这个,这意味着我的方向不好。


有什么建议?


有没有一种我完全不知道的更简单的方法来做这样的事情?


command我应该自己从头开始构建一个装饰器并坚持使用discord.Client而不是尝试添加client.command吗?


德玛西亚99
浏览 186回答 1
1回答

湖上湖

我认为您根本不需要扩展的功能Command。相反,您可以拥有提供您正在寻找的功能的机器人范围on_command_error和 事件。on_command_completion唯一的问题是返回值。最简单的方法可能是分配一个未使用的属性,ctx而不是尝试捕获返回值(您也可以使用返回值引发自定义错误)from discord.commands.ext import Bot, BadArgument, MissingRequiredArgumentimport sysbot = Bot("!")@bot.command()async def some_command(ctx):    ctx.return_value = 1@bot.eventasync def on_command_error(ctx, error):    if isinstance(error, BadArgument):        await ctx.send("That's a bad argument")    elif isinstance(error, MissingRequiredArgument):        await ctx.send("You're missing an argument")    else:        # This is what the standard on_command_error does        print('Ignoring exception in command {}:'.format(context.command), file=sys.stderr)        traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr)@bot.eventasync def on_command_completion(ctx):    await ctx.send(str(ctx.return_value))bot.run("TOKEN")
随时随地看视频慕课网APP

相关分类

Python
我要回答