我的冷却器装饰器无法正常运行,该如何解决?

时间:2019-09-01 04:45:33

标签: python discord.py python-decorators

因此,我尝试制作自己的装饰器,与discord.py模块中提供给我们的内置冷却器装饰器非常相似,不同之处在于,我试图使其在常规函数(例如非“ @client”)上运行。命令async def myCommand()“函数)。

我有一个函数,当用户说“你好”时会向用户说“你好”,但是我不希望他们一遍又一遍地向用户发送垃圾邮件,并导致机器人也向其发送垃圾邮件。这是我目前所拥有的:

@client.event
async def on_message(message):
    if message.content == "hello":
        try: 
            await sayHello(message)
        except Exception as err:
            print(err)

helloCooldown = commands.CooldownMapping.from_cooldown(1.0, 20.0, BucketType.user)
async def sayHello(message):

    bucket = helloCooldown.get_bucket(message)
    retry_after = bucket.update_rate_limit()
    if retry_after:
        return # exits function if on cooldown / is rate limited

    author = message.author
    channel = message.channel

    await channel.send(f"Hello, {author.name}")

我创建的装饰器接受放置在非命令函数上的速率,每和类型(类似于内置的):

def myCooldown(rate, per, type):

    def outer(func):

        def inner(*args):

            cd = commands.CooldownMapping.from_cooldown(rate, per, type)

            bucket = cd.get_bucket(args[0]) # get 'message' argument from the original function

            retry_after = bucket.update_rate_limit()
            if retry_after:
                return # exit out if its on cooldown/ rate limited
            else:
                return func # executes function if not on cooldown

        return inner

    return outer

@myCooldown(1.0, 20.0, BucketType.user)
async def sayHello(message):
    # say hello

预期的行为是,如果被调用,它将保持冷却20秒,然后再次说“你好”。但是,我收到错误消息“ Object function cant be used in 'await' expression”。我该如何修复我的装饰器使其按我打算的方式工作?

1 个答案:

答案 0 :(得分:0)

当您尝试await sayHello(message)时,首先执行sayHello(message)(实际上是inner(message)),并返回func

您的程序尝试运行await func,这实际上没有意义,因此会引发错误。

您需要更改inner,以便它返回一个等待对象。这意味着它不能返回None,因此您应该引发一个错误。

from discord import DiscordException

class FunctionOnCooldown(DiscordException):
    pass 

def myCooldown(rate, per, type):
    def outer(func):
        cd = commands.CooldownMapping.from_cooldown(rate, per, type)
        def inner(message, *args, **kwargs):
            bucket = cd.get_bucket(message) 

            retry_after = bucket.update_rate_limit()
            if retry_after:
                raise FunctionOnCooldown
            else:
                return func(*args, **kwargs) # executes function if not on cooldown

        return inner

    return outer