Как сделать аргумент master необязательным в функции инициации виджета tkinter python?

Вопрос вроде бы простой, но я не знаю, как его решить.

Есть код:

import tkinter as tk


class MainWindow(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)


class MyButton(tk.Button):
    global root

    def __init__(self, master=root):
        tk.Button.__init__(self, master)
        self.pack()


root = MainWindow()
frame1 = tk.Frame(root)
frame1.pack()
button1 = MyButton()
button2 = MyButton(master=frame1)
root.mainloop()

Хочу, чтобы работали оба варианта при вызове функции __init__ в классе MyButton:

  1. Если аргумент master не указан, то используется значение этого аргумента по умолчанию master=root

button1 = MyButton()

  1. Если указано значение аргумента master, то оно используется вместо значения по умолчанию

button2 = MyButton(master=frame1)

Происходит ошибка

NameError: name 'root' is not defined

в строке def __init__(self, master=root):


Ответы (1 шт):

Автор решения: insolor

Укажите None как параметр по-умолчанию. При передаче None в качестве родительского элемента tkinter считает родительским главное окно (первый созданный объект Tk, если он существует, или создает новый). Детали реализации можно посмотреть в tkinter/__init__.py (вкратце, первый созданный объект Tk записывается в глобальную переменную _default_root, потом это значение используется как родитель по умолчанию). Для передачи параметров в родительский класс можно использовать функцию super(), в этом случае не нужно будет передавать self:

import tkinter as tk


class MainWindow(tk.Tk):
    def __init__(self):
        super().__init__()


class MyButton(tk.Button):
    def __init__(self, master=None):
        super().__init__(master)
        self.pack()


root = MainWindow()
frame1 = tk.Frame(root)
frame1.pack()
button1 = MyButton()
button2 = MyButton(master=frame1)
root.mainloop()
→ Ссылка