You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更新Tkinter按钮且避免内存泄漏?

问题

每次执行display_names(gender)时,gender_selected的值会决定哪些名称按钮被禁用。似乎该函数之前调用所占用的内存从未被释放,请问此判断是否正确?若正确,如何编写代码避免内存泄漏?

以下是示例代码:

from tkinter import *
import tkinter as tk

root = Tk()

gender_selected = tk.StringVar()
gender_selected.set('M')

def display_names(gender):
    if gender == 'M': 
        male_state = ACTIVE
        female_state = DISABLED
    else: 
        male_state = DISABLED
        female_state = ACTIVE
    buttn1 = Radiobutton(root, text = 'Bill', value = 'Bill', state = male_state)
    buttn1.place(x=10, y=110)
    buttn2 = Radiobutton(root, text = 'Bob', value = 'Bob', state = male_state)
    buttn2.place(x=10, y=140)
    buttn3 = Radiobutton(root, text = 'Mary', value = 'Mary', state = female_state)
    buttn3.place(x=10, y=170)
    buttn4 = Radiobutton(root, text = 'Sue', value = 'Sue', state = female_state)
    buttn4.place(x=10, y=200)
    if gender == 'M': buttn1.select()
    else: buttn3.select()
    Radiobutton(root, text="Male", variable = gender_selected, value = 'M', 
    command = lambda: display_names(gender_selected.get())).place(x=10, y=30)
    Radiobutton(root, text="Female", variable = gender_selected, value = 'F', 
    command = lambda: display_names(gender_selected.get())).place(x=10, y=60)
  
display_names(gender_selected.get())
 
root.geometry("150x250")
mainloop()
回答

你的判断是正确的。每次调用display_names时,都会重新创建8个Radiobutton控件(4个名称按钮+2个性别按钮),这些旧控件虽然被新控件在视觉上覆盖,但仍然被父组件root持有引用,Python垃圾回收机制无法回收这些无用控件,最终导致内存泄漏。

解决思路

不要每次调用函数都创建新控件,而是提前创建所有需要的控件,在函数中仅修改控件的状态和选中状态,具体实现如下:

from tkinter import *
import tkinter as tk

root = Tk()
root.geometry("150x250")

gender_selected = tk.StringVar()
gender_selected.set('M')

# 提前创建所有名称单选按钮
buttn1 = Radiobutton(root, text='Bill', value='Bill')
buttn1.place(x=10, y=110)
buttn2 = Radiobutton(root, text='Bob', value='Bob')
buttn2.place(x=10, y=140)
buttn3 = Radiobutton(root, text='Mary', value='Mary')
buttn3.place(x=10, y=170)
buttn4 = Radiobutton(root, text='Sue', value='Sue')
buttn4.place(x=10, y=200)

# 提前创建性别单选按钮,仅创建一次
Radiobutton(root, text="Male", variable=gender_selected, value='M', 
            command=lambda: display_names(gender_selected.get())).place(x=10, y=30)
Radiobutton(root, text="Female", variable=gender_selected, value='F', 
            command=lambda: display_names(gender_selected.get())).place(x=10, y=60)

def display_names(gender):
    if gender == 'M': 
        male_state = ACTIVE
        female_state = DISABLED
        buttn1.select()
    else: 
        male_state = DISABLED
        female_state = ACTIVE
        buttn3.select()
    
    # 仅修改现有控件的状态
    buttn1.config(state=male_state)
    buttn2.config(state=male_state)
    buttn3.config(state=female_state)
    buttn4.config(state=female_state)

# 初始化控件状态
display_names(gender_selected.get())

mainloop()

额外优化:分组管理控件

可以将同类型按钮分组存储,让状态修改代码更简洁:

from tkinter import *
import tkinter as tk

root = Tk()
root.geometry("150x250")

gender_selected = tk.StringVar()
gender_selected.set('M')

# 分组创建并布局按钮
male_buttons = [
    Radiobutton(root, text='Bill', value='Bill'),
    Radiobutton(root, text='Bob', value='Bob')
]
female_buttons = [
    Radiobutton(root, text='Mary', value='Mary'),
    Radiobutton(root, text='Sue', value='Sue')
]

for idx, btn in enumerate(male_buttons):
    btn.place(x=10, y=110 + idx*30)
for idx, btn in enumerate(female_buttons):
    btn.place(x=10, y=170 + idx*30)

# 性别按钮仅创建一次
Radiobutton(root, text="Male", variable=gender_selected, value='M', 
            command=lambda: display_names(gender_selected.get())).place(x=10, y=30)
Radiobutton(root, text="Female", variable=gender_selected, value='F', 
            command=lambda: display_names(gender_selected.get())).place(x=10, y=60)

def display_names(gender):
    if gender == 'M': 
        male_state = ACTIVE
        female_state = DISABLED
        male_buttons[0].select()
    else: 
        male_state = DISABLED
        female_state = ACTIVE
        female_buttons[0].select()
    
    # 批量修改按钮状态
    for btn in male_buttons:
        btn.config(state=male_state)
    for btn in female_buttons:
        btn.config(state=female_state)

display_names(gender_selected.get())
mainloop()

这种方式每次调用函数只会修改现有控件的属性,不会生成新控件,从根源上避免了内存泄漏。

内容的提问来源于stack exchange,提问作者Ted Ersek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 05:40:54