Метод w.destroy() не удаляет виджет tkinter?

Я выполнил следующие команды в интерпретаторе Python и обнаружил, что метод w.destroy() виджета tkinter не уничтожает (т. е. не уничтожает существование) виджета tkinter.

>>> root=tk.Tk()
>>> a = ttk.Button(root, text = "Button")
>>> a.grid(row=0, column=0)
>>> a
    <tkinter.ttk.Button object .!button>
>>> a.destroy()
>>> a
    <tkinter.ttk.Button object .!button>
>>> a.grid(row=0, column=0)
    Traceback (most recent call last):
      File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
        exec(code, self.locals)
      File "<pyshell#23>", line 1, in <module>
      File "/usr/lib/python3.10/tkinter/__init__.py", line 2522, in grid_configure
        self.tk.call(
    _tkinter.TclError: bad window path name ".!button"
>>> b
    Traceback (most recent call last):
      File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
        exec(code, self.locals)
      File "<pyshell#24>", line 1, in <module>
    NameError: name 'b' is not defined
>>> del a
>>> a
    Traceback (most recent call last):
      File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
        exec(code, self.locals)
      File "<pyshell#26>", line 1, in <module>
    NameError: name 'a' is not defined
>>> root.destroy()
>>> root
    <tkinter.Tk object .>
>>> del root
>>> root
    Traceback (most recent call last):
      File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
        exec(code, self.locals)
      File "<pyshell#30>", line 1, in <module>
    NameError: name 'root' is not defined
>>> 

Цитирую документацию:

w.destroy()
Calling w.destroy() on a widget w destroys w and all its children.

В приведенном выше примере, хотя a.destroy() удалил внешний вид ttk.Button и не позволил a запускать другие методы tkinter, a по-прежнему распознается как объект <tkinter.ttk.Button object .!button>, т. е. существование a не было удалено из интерпретатора Python. Только после удаления a с помощью команды del a возникло исключение NameError: name 'a' is not defined при вызове a. Тот же результат виден в root.destroy().

Я думаю, что сопровождающим пакета tkinter необходимо включить команду del w (здесь w относится к любому виджету tkinter) к ее методу .destroy(). В противном случае пользователям tkinter теперь необходимо запускать команду del w после каждого метода w.destroy(), чтобы обеспечить чистоту своего кода Python. Мои рассуждения здравы?

Следуя мыслям моего комментария, ниже приведен пример метода класса, удаляющего атрибут класса:

>>> class App(tk.Frame):
        def __init__(self, master, **kw):
            super().__init__(master, bg = "pink")
            self.master = master
            self.bn = tk.Button(self, text = "Button", bg = "cyan", width=10, height=2)
            self.bn.grid(row=0, column=0)
        def eradicate(self):
            del self.bn

>>> root = tk.Tk()
>>> root.geometry("150x150+10+10")
    ''
>>> app = App(root)
>>> app.grid(row=0, column=0)
>>> root.columnconfigure(0, weight=1)
>>> root.rowconfigure(0, weight=1)
>>> app.eradicate()
>>> app.bn
    Traceback (most recent call last):
      File "/usr/lib/python3.10/idlelib/run.py", line 578, in runcode
        exec(code, self.locals)
      File "<pyshell#116>", line 1, in <module>
    AttributeError: 'App' object has no attribute 'bn'

Вызов функции не может изменить значение переменной, которую вы передаете в качестве аргумента. .Поэтому w.destroy() не может изменить значение w.

Barmar 15.09.2023 17:41

@Бармар принял к сведению. Нужно ли пользователю запускать del w? Или уничтожение w более удачно осуществляется сборщиком мусора Python, и программист может избежать этой проблемы?

Sun Bear 15.09.2023 18:36

Просто позвольте сборщику мусора разобраться с этим.

Barmar 15.09.2023 18:37

@Barmer У меня есть сомнения по поводу твоего первого комментария. w.destroy() — это метод класса Python, а не функция. Таким образом, запуск метода класса для атрибута класса может изменить значение атрибута класса (или удалить атрибут класса, если это необходимо).

Sun Bear 15.09.2023 19:42

Конечно, методы могут назначать и другие переменные и атрибуты. Но у них нет доступа к переменной, к которой они обращаются.

Barmar 15.09.2023 19:43
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что сопровождающим пакета tkinter необходимо включить команду del w (здесь w относится к любому виджету tkinter) в его метод .destroy(). В противном случае пользователям tkinter теперь необходимо запускать команду del w после каждого метода w.destroy(), чтобы обеспечить чистоту своего кода Python. Мои рассуждения здравы?

Нет, ваши рассуждения не верны. Объект не может уничтожить переменные, ссылающиеся на объект. Например, на один объект может ссылаться более чем одна переменная. Как код узнает, какую переменную вы хотите уничтожить? А что, если вы не хотите, чтобы ссылка была уничтожена? Бывают случаи, когда вы хотите сохранить ссылку, даже если сам виджет был уничтожен.

Практически никогда не должно возникать необходимости вызывать del для переменной, содержащей ссылку на виджет. Python имеет возможность автоматически уничтожать эти объекты, когда обнаруживает, что они больше не используются (так называемый сборщик мусора).

Другие вопросы по теме