有没有办法捕获和处理创建 Tkinter 窗口的无限递归函数?

问题描述 投票:0回答:1

我有一个学生提交了这样的函数:

def infinite_windows():
    window = tkinter.Tk()
    infinite_windows()

我已经在 try- except 块内测试了一些东西。 我的代码报告了 RecursionError,但下次它要求用户输入时它会冻结我的桌面,我必须终止 Python。 以下代码挂起,但仅当包含 input() 调用时:

import tkinter

def infinite_windows():
    window = tkinter.Tk()
    infinite_windows()
    
try:
    infinite_windows()
except Exception as e:
    print("caught the exception!")
    print(e)

input("hi there") #hangs here

有什么方法可以让我处理这种行为并继续运行 Python,而不删除对 input() 的调用?

python python-3.x tkinter recursion
1个回答
0
投票

我将此作为可能的解决方案:

import tkinter


def infinite_windows():
    window = tkinter.Tk()
    infinite_windows()


# Store all Tk objects in an array
_all_windows = []

class _Tk(tkinter.Tk):
    def __init__(self, *args, **kwargs):
        _all_windows.append(self) # Add this Tk object in the array
        super().__init__(*args, **kwargs)
tkinter.Tk = _Tk # Replace tkinter's Tk class with our own


try:
    infinite_windows()
except Exception as e:
    print("caught the exception!")
    print(e)
    
for window in _all_windows:
    try:
        window.destroy()
    except tkinter.TclError:
        # If the window wasn't fully created/already was destroyed
        pass
_all_windows.clear() # Clear the array

input("? ")

基本上,我用继承自

tkinter.Tk
的我自己的类覆盖
tkinter.Tk
(不会导致递归问题,因为我的类是在替换
tkinter.Tk
之前构建的)。在我自己的班级中,我跟踪全局列表中的所有
tkinter.Tk
对象并在最后销毁它们。

这种方法有效(在带有 Wayland 的 Ubuntu 上),但有一些限制:

  • 实际上并没有释放所有
    tkinter.Tk
    对象所需的 1.9 GB RAM。我们对此无能为力,因为 python 不愿意将 RAM 释放回操作系统
  • 如果学生执行像这样存储原始
    tkinter.Tk
    类的操作,则此方法不起作用:
import tkinter

def infinite_windows(window_class=tkinter.Tk):
    window = window_class()
    infinite_windows()

要解决该问题,您可以将覆盖

tkinter.Tk
的代码移到学生代码之前(但如果学生尝试从
__future__
导入某些内容,则会引发错误)

© www.soinside.com 2019 - 2024. All rights reserved.