Python中有两种类型的递归,一种是有效的,另一种则不然

Two types of Recursion in Python, one works, the other doesnt

为什么这段代码会因运行时错误而爆炸:调用python对象时超过了最大递归深度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Tkinter as tk

counter = 0
def counter_label(label):
    global counter
    counter += 1
    label.config(text=str(counter))
    label.after(1000, counter_label(label))  

root = tk.Tk()
root.title("Counting Seconds")
label = tk.Label(root, fg="green")
label.pack()
counter_label(label)
button = tk.Button(root, text='Stop', width=25, command=root.destroy)
button.pack()
root.mainloop()

下面的计数器标签定义没有?

1
2
3
4
5
6
7
def counter_label(label):
    def count():
        global counter
        counter += 1
        label.config(text=str(counter))
        label.after(1000, count)
    count()


看看这行:

1
label.after(1000, counter_label(label))

与此完全相同:

1
2
foo = counter_label(label)
label.after(1000, foo)

看到问题了吗?你马上打电话给counter_label,后者立刻打电话给counter_label,后者立刻打电话给……

使用after时,必须给它一个函数的引用。需要为after提供附加参数:

1
label.after(counter_label, label)


在第一个代码片段label.after(1000, counter_label(label))中,这个代码是递归调用的,而不会中断。对于任何递归,都需要一个基本条件,递归才能将其打破。

可能的解决方案

1
2
3
4
5
6
7
def counter_label(label):
    global counter
    counter += 1
    if counter == 10: # this is the base condition
        return counter; # anything that you want.
    label.config(text=str(counter))
    label.after(1000, counter_label(label))

第二个代码段不是递归label.after(1000, count),您只是将函数引用作为第二个参数传递给label.after。