Объектно-ориентированное программирование (ООП) - это технология в которой объекты создаются с помощью классов. Класс описывает свойства объекта или объектов, создаваемых на его основе. Объект - это экземпляр класса.

Классы создаются с помощью ключевого слова class. Например:

class animal:
    pass

class flora(object):
    pass

class dog(animal):
    pass

Лист. 1. Создание классов

Классы animal и flora созданы на основе базового класса object, класс dog создан на основе класса animal. Класс dog наследует свойства класса animal, и является его наследником. Класс animal является суперклассом по отношению к классу dog.

from tkinter import *               # графическая библиотека


class Btn(Button):
    pass


Btn(width=3, height=2, font=('times', 24, 'bold'),
    text="Yes").pack(expand=YES, fill=BOTH, side=LEFT)


mainloop()                          # главный цикл программы

Лист. 2. Класс Btn наследник класса Button из библиотеки tkinter.

Рис. 1. Кнопка типа (класса) Btn создана конструктором суперкласса Button.

Кнопка на рисунке 1 создана программой листинг 1. Создание кнопки как объекта (экземпляра класса) в программе листинг 1 произошло когда мы использовали имя класса Btn как функцию, с круглыми скобками Btn(). Параметры, перечисленные в круглых скобках при вызове конструктора класса Btn описаны в классе Button в библиотеке tkinter. Здесь мы их не рассматриваем.

К объекту класса Btn в программе листинг 1 применяется (вызывается) метод (встроенная функция) pack(). Функция pack(), так же, как и упомянутые выше параметры класса Button, является свойством класса Button. Методы объектов вызываются с использованием составного имени через точку:

Имя_объекта.имя_метода(параметры)

Имя объекта (точнее ссылка на объект) класса Btn в программе листинг 1 возвращается в то место где был вызван конструктор Btn() с параметрами.

На самом деле, пока в программе листинг 1 в классе Btn не объявлен свой конструктор объектов - функция __init__, при создании экземпляров класса Btn используется метод __init__() суперкласса Button.

Создавая пользовательский класс Btn, мы планируем снабдить его дополнительными свойствами. Нет большого смысла в новом классе, который полностью повторяет свойства суперкласса. В программу листинг 2 в класс Btn мы добавим свой конструктор __init__(). Заметим, что у функции __init__() должен быть, как минимум, один обязательный параметр self. И любые другие методы класса, так же как и метод __init__(), должны иметь в качестве первого передаваемого параметра параметр self. Параметр self является ссылкой на создаваемый объект (экземпляр класса). Self программистом внутри класса не определяется, а только используется. При вызове методов объекта параметр self не указывают. 

from tkinter import *                           # графическая библиотека


class Btn(Button):
    def __init__(self, color, *args, **kwards): # конструктор объекта класса
        print(args, kwards)
        super().__init__(*args, **kwards)       # вызов конструктора суперкласса
        self.config(bg=color)
        self.pack(expand=YES, fill=BOTH, side=LEFT)


tk = Tk()                                       # главное окно программы

# создание объекта типа Btn
Btn('pink', tk, width=3, height=2,
    text="Yes", font=('times', 24, 'bold'))


mainloop()                                      # главный цикл программы

Лист. 3. Пример использования параметров *args **kwargs для передачи аргументов в функцию.

(<tkinter.Tk object .>,) {'width': 3, 'height': 2, 'text': 'Yes', 'font': ('times', 24, 'bold')}

Лист. 4. Вывод из программы в командную строку.

В программе листинг 3 *args позволяет передать в параметр args позиционные аргументы, представляемые в виде кортежа, а **kwargs передаёт в kwargs именованные аргументы, представленные в виде словаря.

Рис. 2. Результат работы программы листинг 8.

Цвет кнопки в конструктор класса Btn передан как параметр 'pink'.

Игровое поле

Напишем на Python с графической библиотекой tkinter программу (заготовку) шаблон для логических  игр c прямоугольным полем в клетку. В качестве клеток на поле будем использовать кнопки.

Перечислим примеры логических игр на поле в клетку:

  1. Шашки, 
  2. Шахматы,
  3. Го, 
  4. Уголки, 
  5. Крестики нолики,
  6. Линии (Lines98), 
  7. Пазлы - головоломки:
    1. Пятнашки, 
    2. Что ест уж, 
    3. Чайный сервиз,
  8. Flip-Flop, 
  9. Memory
  10. Сапёр,
  11. Пег,
  12. Игры с цифрами:
    1. 2048
    2. Судоку
    3. Number Match
  13. Трубопровод...

Для создания компьютерных игр в клетку, где в качестве клеток будут использоваться кнопки напишем программу на языке программирования Python с использованием графической библиотеки tkinter.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы


class Btn(Button):
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)


Btn(width=3, height=2, font=('times', 24, 'bold'))

mainloop()                          # главный цикл программы

Лист. 5. Одна кнопка.

Рис. 3. Кнопка создана программой лист. 5.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы

class Btn(Button):
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)


f = Frame()                     # Фрейм
f.pack(expand=YES, fill=BOTH)
for j in range(column):
    Btn(f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # главный цикл программы

Лист. 6. Кнопки во фрейме.

Рис. 4. Ряд кнопок создан программой лист. 6.

from tkinter import *               # Графическая библиотека
column = 3                          # Столбцы
row = 3                             # Строки

class Btn(Button):                  # Класс Btn
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)


for i in range(row):
    f = Frame()                     # Фреймы (строки)
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):         # Колонки
        Btn(f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # Главный цикл программы

Лист. 7. GUI приложение с решёткой кнопок.

Рис. 5. Приложение созданное программой листинг 7.

from tkinter import *               # Графическая библиотека
column = 3                          # Столбцы
row = 3                             # Строки

class Btn(Button):                  # Класс Btn
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

    def play(self):                 # Обработчик нажатия на кнопку
        self.config(text='*')


for i in range(row):
    f = Frame()                     # Фреймы (строки)
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):         # Колонки
        Btn(f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # Главный цикл программы

Лист. 8. В программу, в класс Btn добавлен метод play().

Рис. 6. Приложение созданное программой листинг 8.

Метод play(), экземпляров класса Btn, по щелчку мышью на кнопке выводит на эту кнопку звёздочку (*).

Крестики нолики

from tkinter import *               # Графическая библиотека
column = 3                          # Столбцы
row = 3                             # Строки

class Btn(Button):                  # Класс Btn
    who = True                      # Кто ходит
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

    def play(self):                 # Обработчик нажатия на кнопку
        if Btn.who:
            self.config(text='X')
        else:
            self.config(text='0')
        Btn.who = not(Btn.who)


for i in range(row):
    f = Frame()                     # Фреймы (строки)
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):         # Колонки
        Btn(f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # Главный цикл программы

Лист. 9.

Рис. 7.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# tic-tac-toe.py
# Copyright (C) 2025 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# tic-tac-toe.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# tic-tac-toe.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # Графическая библиотека
column = 3                          # Столбцы
row = 3                             # Строки

class Btn(Button):                  # Класс Btn
    who = True                      # Кто ходит
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

    def play(self):                 # Обработчик нажатия на кнопку
        if self.cget('text') != '': return
        self.config(text='X' if Btn.who else '0')
        Btn.who = not(Btn.who)


for i in range(row):
    f = Frame()                     # Фреймы (строки)
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):         # Колонки
        Btn(f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # Главный цикл программы

Лист. 10.

Рис. 8.

Что ест уж

арвар

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки

class Btn(Button):
    playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play,
                         text=self.playground[num])
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        
    def play(self):                 # обработчик нажатия на кнопку
        self.config(text=' ')


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # главный цикл программы

Лист. 14.

Рис. 9.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки

class Btn(Button):
    playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play,
                         text=self.playground[num])
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        
    def play(self):                 # обработчик нажатия на кнопку
        n = self.num
        m = self.playground.index(" ")
        self.config(text=' ')
        self.playground[m], self.playground[n] = self.playground[n], " "


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # главный цикл программы

Лист. 15.

Рис. 10.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки

class Btn(Button):
    playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play,
                         text=self.playground[num])
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        self.automove()
        
    def play(self):                 # обработчик нажатия на кнопку
        n = self.num
        m = self.playground.index(" ")
        self.config(text=' ')
        self.playground[m], self.playground[n] = self.playground[n], " "
        self.automove()

    def automove(self):             # функция кнопки с пробелом
        self.config(text=self.playground[self.num])
        if self.cget('text') == " ":
            self.after(300, self.automove)


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # главный цикл программы

Лист. 16. В программе, в функции Btn.automove() используется рекурсивный отложенный вызов с помощью функции after().

Рис. 11.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки

class Btn(Button):
    playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play,
                         text=self.playground[num])
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        self.automove()
        
    def play(self):                 # обработчик нажатия на кнопку
        n = self.num
        m = self.playground.index(" ")
        if (n in [m+1, m-1] and m // column == n // column
                 or n in [m-column, m+column]):
            self.config(text=' ')
            self.playground[m], self.playground[n] = self.playground[n], " "
            self.automove()

    def automove(self):             # функция кнопки с пробелом
        self.config(text=self.playground[self.num])
        if self.cget('text') == " ":
            self.after(300, self.automove)


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))


mainloop()                          # главный цикл программы

Лист. 17. В программе, в функции Btn.automove() используется рекурсивный отложенный вызов с помощью функции after(). В функцию play() добавлена функция if с правилами игры в условии.

Рис. 12.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки
playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле


class Btn(Button):
    space = 8
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play)
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        
    def play(self):                 # обработчик нажатия на кнопку
        n = self.num
        m = Btn.space
        if (n in [m+1, m-1] and m // column == n // column
                 or n in [m-column, m+column]):
            playground[m].set(playground[n].get())
            playground[n].set(" ")
            Btn.space = n


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        playground[n] = StringVar(f, playground[n])
        Btn(n, f, width=3, height=2, font=('times', 24, 'bold'),
            textvariable=playground[n])


mainloop()                          # главный цикл программы

Лист. 18. Свойство textvariable объектов класса Button связано с переменной типа StringVar.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки
btn = []                            # список кнопок

class Btn(Button):
    playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле
    def __init__(self, num, *args, **kwards):
        super().__init__(*args, **kwards, command=self.play,
                         text=self.playground[num])
        self.pack(expand=YES, fill=BOTH, side=LEFT)
        self.num = num
        
    def play(self):                 # обработчик нажатия на кнопку
        n = self.num
        m = self.playground.index(" ")
        if (n in [m+1, m-1] and m // column == n // column
                 or n in [m-column, m+column]):
            self.config(text=' ')
            btn[m].config(text=self.playground[n])
            self.playground[m], self.playground[n] = self.playground[n], " "


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        btn += [Btn(n, f, width=3, height=2, font=('times', 24, 'bold'))]


mainloop()                          # главный цикл программы

Лист. 19. Программа содержит список объектов класса Button, то есть, объекты поименованы.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки
btn = []                            # список кнопок
playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле


class Btn(Button):
    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

        
def play(n):                     # обработчик нажатия на кнопку
    m = playground.index(" ")
    if (n in [m+1, m-1] and m // column == n // column
        or n in [m-column, m+column]):
        playground[m], playground[n] = playground[n], " "
        btn[n].config(text=" ")
        btn[m].config(text=playground[m])


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
                    text=playground[n], command=lambda n=n: play(n))]


mainloop()                          # главный цикл программы

Лист. 20. Программа с lambda функцией.

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки
btn = []                            # список кнопок
playground = list('ЧТОЕСТЖУ ')      # виртуальное игровое поле


class Btn(Button):

    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

    class Letter:
        def __set__(self, instance, value):
            instance.config(text=value)

    letter = Letter()

        
def play(n):                     # обработчик нажатия на кнопку
    m = playground.index(" ")
    if (n in [m+1, m-1] and m // column == n // column
        or n in [m-column, m+column]):
        btn[m].letter, btn[n].letter = playground[m], playground[n] = playground[n], " " 
        

for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
                    text=playground[n], command=lambda n=n: play(n))]


mainloop()                          # главный цикл программы

Лист. 21.  Класс Btn с дескриптором Letter, который содержит функцию __set__ .

#!/usr/bin/env python
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- 
#
# snake.py
# Copyright (C) 2021 Aleksandr Diorditsa, see <https://adior.ru>
# I want to thank all my students for the inspiration they give me.
#
# snake.py is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# snake.py is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.

from tkinter import *               # графическая библиотека
column = 3                          # столбцы
row = 3                             # строки
btn = []                            # список кнопок


class Btn(Button):

    def __init__(self, *args, **kwards):
        super().__init__(*args, **kwards)
        self.pack(expand=YES, fill=BOTH, side=LEFT)

    class Letter:
        def __set__(self, instance, value):
            instance.config(text=value)
        def __get__(self, instance, owner):
            return instance.cget('text')
        
    letter = Letter()

        
def play(n):                     # обработчик нажатия на кнопку
    m = [i.letter for i in btn].index(" ")
    if (n in [m+1, m-1] and m // column == n // column
        or n in [m-column, m+column]):
        btn[m].letter, btn[n].letter = btn[n].letter, " " 


for i in range(row):
    f = Frame()                     # Фреймы
    f.pack(expand=YES, fill=BOTH)
    for j in range(column):
        n = i * column + j
        btn += [Btn(f, width=3, height=2, font=('times', 24, 'bold'),
                    text='ЧТОЕСТЖУ '[n], command=lambda n=n: play(n))]

mainloop()                          # главный цикл программы

Лист. 22. Класс Btn с дескриптором Letter, который содержит функции __set__ и __get__.

Литература: proglib

stackoverflow