改进当前的setInterval实现

12
我试图找出如何在Python中制作一个可以取消的setInterval,而不必创建一个全新的类来完成这项任务,我已经找到了方法,但现在我想知道是否有更好的方法。
下面的代码似乎运行良好,但我还没有完全测试过。
import threading
def setInterval(func, sec):
    def inner():
        while function.isAlive():
            func()
            time.sleep(sec)
    function = type("setInterval", (), {}) # not really a function I guess
    function.isAlive = lambda: function.vars["isAlive"]
    function.vars = {"isAlive": True}
    function.cancel = lambda: function.vars.update({"isAlive": False})
    thread = threading.Timer(sec, inner)
    thread.setDaemon(True)
    thread.start()
    return function
interval = setInterval(lambda: print("Hello, World"), 60) # will print Hello, World every 60 seconds
# 3 minutes later
interval.cancel() # it will stop printing Hello, World 

有没有一种方法可以在不使用继承自 threading.Thread 的专用类或使用 type("setInterval", (), {}) 的情况下完成上述操作?或者我只能在专门制作一个类和继续使用 type 之间做出选择吗?


使用 type 相当于在 setInterval 内部显式声明一个内部类。 - roippi
1个回答

30

为了每隔interval秒重复调用一个函数,并能够取消未来的调用:

from threading import Event, Thread

def call_repeatedly(interval, func, *args):
    stopped = Event()
    def loop():
        while not stopped.wait(interval): # the first call is in `interval` secs
            func(*args)
    Thread(target=loop).start()    
    return stopped.set

例子:

cancel_future_calls = call_repeatedly(60, print, "Hello, World")
# ...
cancel_future_calls() 
注意:此版本在每次调用后都会等待约interval秒,无论func(*args)花费多长时间。如果需要类似节拍器的执行,则可以使用定时器(timer())来锁定执行:stopped.wait(interval)可以替换为stopped.wait(interval - timer() % interval),其中timer()定义了当前时间(可能是相对时间)以秒为单位,例如time.time()。请参见什么是在Python中每x秒重复执行函数的最佳方法?

谢谢,这绝对是一个改进,看起来更清晰了。 - user3234209
在后台运行时要小心,当您的主线程抛出未处理的异常时 - 将 # ... 包装在 try: (...) finally: cancel_future_calls() 中。(这包括常见的 KeyboardInterrupt)。 - Tomasz Gandor
1
@TomaszGandor:你可以传递 daemon=True,这样后台线程如果程序意外退出就会死亡。或者将其转换为上下文管理器:with calling_repeatedly(interval, func, *args): <代码块> 如果你想在执行代码块的同时重复执行函数,例如收集一些性能统计数据:内存、CPU 百分比等等。还可能有其他情况。返回可能取消未来调用的句柄是最灵活的方法。 - jfs
如何在函数内停止间隔。 - Coder Gautam YT
@CoderGautamYT:就像使用Python中的任何其他函数一样,您可以使用“return”退出函数。 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接