我试图添加到client.command
的错误,args,kwargs和函数的处理(client
是discord.ext.commands.Bot
实例)。基本上我试图让我的所有命令都有一些共同的自定义行为。
我最初的想法是创建一个函数,返回一个装饰器,用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
?
我认为你根本不需要扩展Command
的功能。相反,您可以使用机器人范围的on_command_error
和on_command_completion
事件来提供您正在寻找的功能。
唯一的问题是返回值。最简单的方法可能是分配ctx
的未使用属性,而不是尝试捕获返回值(您还可以使用返回值引发自定义错误)
from discord.commands.ext import Bot, BadArgument, MissingRequiredArgument
import sys
bot = Bot("!")
@bot.command()
async def some_command(ctx):
ctx.return_value = 1
@bot.event
async 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.event
async def on_command_completion(ctx):
await ctx.send(str(ctx.return_value))
bot.run("TOKEN")