【问题标题】:Cooldown within an if statementif 语句中的冷却时间
【发布时间】:2019-06-21 19:56:33
【问题描述】:

我正在用 Python 编写一个非常简单的 Twitch 聊天机器人,并且我的所有“命令”都在 if 语句中运行(基本上,如果聊天机器人在聊天中看到它激活的内容)。

但是,我想为 per 命令(或 if 语句)添加大约 3 秒或真正的时间量的冷却时间,以便我可以根据需要对其进行自定义。为此,我尝试了这个(伪代码)

if command is seen in chat
    newtimestamp = create timestamp at now
    if (newtimestamp - previoustimestamp) > 30
        execute the command
        make (previoustimestamp)
    else
        return

但这不起作用,因为显然它在第一次运行时没有检测到 (previoustimestamp),因为它尚未声明,但是当你声明它时,它会在每次运行命令时声明它。

那么有没有办法在 if 语句的开头只声明一次,然后每隔一次就忽略它?还是有其他想法?我仍然是一个非常新手的程序员,所以我很抱歉。

这是一个我想要冷却时间的示例代码,非常简单

if "!redb match" in message:    
   x = str(randint(1, 100))
   realmessage = message.replace('!redb ship ', '')
   array = realmessage.split(' ')
   person1 = array[0]
   person2 = array[1]
   if ((9 - 2) > 5):
      sendMessage(s, person1 + " and " + person2 + "have a " + x + "% love compatibility <3")           
   else:
      break

【问题讨论】:

    标签: python if-statement bots chatbot twitch


    【解决方案1】:

    例如,如果某个条件触发,您可以使用time.sleep(3) 等待 3 秒。这将暂停执行 3 秒。

    编辑:由于您希望这些 if 语句有自己的冷却时间,您可以尝试将其放入一个更复杂的控制循环中

    cooldowns_dict = {"trigger_1": 0, "trigger_2":0}
    
    while(True):
        loop_start = time.time()
        if ("!redb match" in message) and cooldowns_dict["trigger_1"] <= 0:
            # Send message etc.
            cooldowns_dict["trigger_1"] = 3    # Set a 3 second cooldown
    
        time.sleep(0.1)    # Just to stop this looping too fast
        loop_end = time.time()
        # update the cooldowns
        for key, value in cooldowns_dict.items():
            if value > 0:
                cooldowns_dict[key] -= (loop_end - loop_start)
            else:
                cooldowns_dict[key] = 0
    

    【讨论】:

    • 是的,我想过这个问题,但是这不会暂停整个程序而不是 if 语句吗?我想我忘了提到我在同一个文件中有多个其他 if 语句,我希望有自定义冷却并且即使冷却在不同的命令上处于活动状态仍然可以工作..也许我应该以一种方式工作我的 if 语句在不同的文件中,那么这种方法实际上可能有效......
    • @Redicebergz 是的,你是对的,因为 python 是单线程的,这将暂停整个执行。在我的编辑中查看使用控制循环的替代方法。
    【解决方案2】:

    我会使用字典作为时间戳,像previous_timestamp = command_timestamps.get('!redb match', 0) 一样访问它。如果它在字典中,这将为您提供存储的时间戳,如果您使用 time.time() 作为您的时间戳,则为 0(1970 年 1 月 1 日),希望这在过去足够远,不会破坏您的任何冷却时间)。

    【讨论】:

      【解决方案3】:

      您可以为存储上次调用时间的函数编写一个装饰器,如果距离现在太近,则返回 None

      from functools import wraps
      from datetime import datetime, timedelta
      
      
      def cooldown(*delta_args, **delta_kwargs):
          delta = timedelta(*delta_args, **delta_kwargs)
          def decorator(func):
              last_called = None
              @wraps(func)
              def wrapper(*args, **kwargs):
                  nonlocal last_called
                  now = datetime.now()
                  if last_called and (now - last_called < delta):
                      return
                  last_called = now
                  return func(*args, **kwargs)
              return wrapper
          return decorator
      
      @cooldown(seconds=5)
      def foo():
          print("Run")
      
      foo() # Run
      time.sleep(1)
      foo()
      time.sleep(4) 
      foo() # Run
      

      cooldown 的参数被发送到timedelta,因此您应该阅读the documentation 更多关于这些对象的信息

      【讨论】:

      • 很抱歉,在我的代码中实现这一点时遇到了很多麻烦,而且大部分时间仍然感到困惑......我一直在通过不同的解决方案来回走动,但我仍然没有没能做到。我对这个机器人的所有命令都在一个真正的循环中,所以基本上它们都嵌入了 if 语句,所以我需要将 @cooldown 装饰器应用于 def,然后在 if 语句被激活时运行该函数?同样,我收到“nonlocal last_call”的语法错误,我不明白这是在做什么,你能澄清一下吗
      • nonlocal last_called 表示wrapper 中的last_called 与decorator 中的last_called 是同一个变量。这就是它如何“记住”最后一次调用它的时间。至于你的另一点,可能在一个巨大的嵌套块中使用这个逻辑,但你应该考虑将你的代码重构为函数。
      • 好的,所以我只是将所有命令重组为函数,但我仍然收到 last_call 位的错误,给出语法错误。我想我在这里遗漏了一些东西,但我查找的其他示例似乎具有相同的语法
      • 哦,你知道吗,nonlocal 只是 python 3 的东西,我在 2.7,所以我必须解决这个问题,哈哈
      猜你喜欢
      • 2021-05-15
      • 2021-05-02
      • 1970-01-01
      • 2021-03-11
      • 2021-02-16
      • 2021-06-17
      • 2021-12-04
      • 1970-01-01
      相关资源
      最近更新 更多