Tkinter的.after()和递归

Pie*_*olo 1 python recursion tkinter python-3.x

要及时更新小部件,我使用该.after()方法,通常采用以下形式:

def update():
    do_something()
    <widget>.after(<delay>, update)
Run Code Online (Sandbox Code Playgroud)

我的理解是,小部件等待一定的时间然后执行该update()功能,最后小部件在重新执行该功能之前再次等待,等等.

这在我看来很像递归.所以,问题是:.after()实际上是否通过递归方式工作?

如果确实如此,则递归深度存在限制,但以下示例应证明永远不会达到此限制:

from tkinter import *

counter = 0

def count():
    global counter
    counter += 1
    lbl.config(text=counter)
    root.after(10, count)

root = Tk()
lbl = Label(root, text='0')
lbl.pack()
Button(root, text='Start count', command=count).pack()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)

在我的系统中,递归深度的限制是1000,但是这个例子在几秒钟内远远超过了该值,直到我停止它为止.

Nov*_*vel 5

递归意味着函数的当前实例处于保持状态,并创建并运行新实例.after工作方式不同,不是递归.

您可以将mainloop视为维护待办事项列表的无限循环.该列表具有应该运行的功能和时间.mainloop不断检查todo列表,如果要运行todo列表中的项目,则mainloop将从列表中删除该项目并运行它.完成后,它会回到循环并检查列表.该after方法只是为此待办事项列表添加了一个函数以及运行它的时间.


Bry*_*ley 5

据我了解,小部件会等待一定的时间,然后执行 update() 函数,最后小部件会再次等待,然后重新执行该函数,依此类推。

突出显示的部分是错误的。after只是将函数放入队列中。它不会重新执行任何操作。mainloop只需将“之后”队列中的内容弹出并运行一次即可。

所以,问题是: .after() 实际上是否通过递归的方式工作?

编号after应该是命名的add_job_to_queue。它不是递归,它只是将作业放入队列中。

如果是这样,那么递归深度就有一个限制,但下面的例子应该证明永远不会达到这样的限制:

def count():
    global counter
    counter += 1
    lbl.config(text=counter)
    root.after(10, count)
Run Code Online (Sandbox Code Playgroud)

没有达到限制的原因还是因为它不是递归。当您count通过单击按钮进行调用时,它会执行一些工作,然后将一项添加到“之后”队列中。队列的长度现在为一。

当时间到来时,mainloop将从队列中弹出该项目,使队列的长度为零。然后,您的代码将自身添加到队列中,使长度为 1。当时间到来时,mainloop将从队列中弹出该项目,使队列的长度为零。然后, ...