Глава 23 · Ещё больше мини-проектов
Проект 23-1: Калькулятор с Tkinter
Экран, сетка кнопок и функция vychislit_vyrazhenie() — вот и весь калькулятор.
Проект 23-1: Калькулятор с Tkinter
Собираем настоящий калькулятор: экран сверху, кнопки с цифрами и знаками снизу. Идея та же, что и в тренажёре «Крестики-нолики» из главы 19 — сетка кнопок, каждая из которых вызывает одну и ту же функцию с разным аргументом:
sozdanie_knopok.py
KNOPKI = [
("7", 1, 0), ("8", 1, 1), ("9", 1, 2), ("/", 1, 3),
("4", 2, 0), ("5", 2, 1), ("6", 2, 2), ("*", 2, 3),
# ...
]
for podpis, stroka, stolbec in KNOPKI:
knopka = tk.Button(root, text=podpis,
command=lambda s=podpis: na_cifru_ili_znak_nazhali(s))
knopka.grid(row=stroka, column=stolbec, sticky="we")
lambda s=podpis — почему нельзя просто lambda: ...(podpis)
Это тот же самый «капкан позднего связывания замыканий», что мы разбирали в главе 17: без
s=podpis все кнопки запомнили бы одну и ту же, последнюю по циклу переменную podpis — и нажатие любой кнопки вставляло бы один и тот же символ.Вычисляем выражение
Вместо того чтобы писать свой разбор арифметики, используем встроенную функцию
eval() — но осторожно: проверяем, что в
строке нет ничего, кроме цифр и знаков, и запрещаем доступ к встроенным функциям Python:
vychislenie.py
def vychislit_vyrazhenie(vyrazhenie):
dopustimye_simvoly = set("0123456789+-*/(). ")
if not vyrazhenie or not set(vyrazhenie) <= dopustimye_simvoly:
return "Ошибка"
try:
return str(eval(vyrazhenie, {"__builtins__": {}}, {}))
except (SyntaxError, ZeroDivisionError, ValueError):
return "Ошибка"
Почему просто не написать eval(vyrazhenie)?
Обычный
eval() выполнит любой Python-код, который ему передать — например, команду для удаления файлов. Проверка разрешённых символов и пустой словарь {"__builtins__": {}} не дают выражению сделать ничего, кроме простой арифметики.Полный код: 📄 projects/tkinter/calculator/calculator.py
Практика в Jupyter Notebook
23-01-kalkulyator.ipynb · вычисления и последовательности нажатий