Я выполнил следующие команды в интерпретаторе 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'
@Бармар принял к сведению. Нужно ли пользователю запускать del w
? Или уничтожение w
более удачно осуществляется сборщиком мусора Python, и программист может избежать этой проблемы?
Просто позвольте сборщику мусора разобраться с этим.
@Barmer У меня есть сомнения по поводу твоего первого комментария. w.destroy()
— это метод класса Python, а не функция. Таким образом, запуск метода класса для атрибута класса может изменить значение атрибута класса (или удалить атрибут класса, если это необходимо).
Конечно, методы могут назначать и другие переменные и атрибуты. Но у них нет доступа к переменной, к которой они обращаются.
Я думаю, что сопровождающим пакета tkinter необходимо включить команду del w (здесь w относится к любому виджету tkinter) в его метод .destroy(). В противном случае пользователям tkinter теперь необходимо запускать команду del w после каждого метода w.destroy(), чтобы обеспечить чистоту своего кода Python. Мои рассуждения здравы?
Нет, ваши рассуждения не верны. Объект не может уничтожить переменные, ссылающиеся на объект. Например, на один объект может ссылаться более чем одна переменная. Как код узнает, какую переменную вы хотите уничтожить? А что, если вы не хотите, чтобы ссылка была уничтожена? Бывают случаи, когда вы хотите сохранить ссылку, даже если сам виджет был уничтожен.
Практически никогда не должно возникать необходимости вызывать del
для переменной, содержащей ссылку на виджет. Python имеет возможность автоматически уничтожать эти объекты, когда обнаруживает, что они больше не используются (так называемый сборщик мусора).
Вызов функции не может изменить значение переменной, которую вы передаете в качестве аргумента. .Поэтому
w.destroy()
не может изменить значениеw
.