【问题标题】:My cooldown decorator isn't functioning properly, how can I fix this?我的冷却装饰器无法正常工作,我该如何解决?
【发布时间】:2020-01-04 16:23:18
【问题描述】:

所以我尝试制作自己的装饰器,与 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}")

我创建的装饰器采用放置在非命令函数上的速率、per 和类型(类似于内置的):

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”。如何修复我的装饰器,使其按照我的预期工作方式工作?

【问题讨论】:

    标签: python discord.py python-decorators


    【解决方案1】:

    当您尝试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
    

    【讨论】:

    • 我尝试了上面的代码,虽然它没有给出错误,但它并没有使函数进入冷却状态。它仍然允许我和其他人一遍又一遍地使用它。想一想,实际上每次使用装饰器时都会创建一个全新的实例。有没有办法创建该实例,然后检查它当前是否存在?
    • 您可以将cd = ... 行移到inner 之外
    • 一切正常!非常感谢您的帮助,我认为这会更难哈哈
    • 另一种解决方案可能是使inner 成为异步函数,它执行return await func(*args)。我认为这会让你在被屏蔽的情况下继续返回None
    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-14
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多