Калькулятор на Python: обучающие примеры для начинающих и продвинутых
В этой статье собраны несколько вариантов создания калькулятора на Python. Каждый подход решает определённые задачи: от базового ввода-вывода до работы с графическим интерфейсом и обработки командной строки. Для каждого варианта приведён код с пояснениями, а также разобраны типичные ошибки и способы их устранения.
\nОсновное решение: калькулятор с функциями и обработкой ошибок
\nЦель: создать надёжный консольный калькулятор, который корректно обрабатывает деление на ноль и некорректный ввод.
\n\ndef add(a, b):\n return a + b\n\ndef subtract(a, b):\n return a - b\n\ndef multiply(a, b):\n return a * b\n\ndef divide(a, b):\n if b == 0:\n raise ValueError(\"Деление на ноль\")\n return a / b\n\noperations = {\n '1': add,\n '2': subtract,\n '3': multiply,\n '4': divide\n}\n\nwhile True:\n print(\"Выберите операцию:\\n1. Сложение\\n2. Вычитание\\n3. Умножение\\n4. Деление\\n5. Выход\")\n try:\n choice = input(\"Введите номер: \")\n if choice == '5':\n break\n if choice not in operations:\n print(\"Неверный выбор.\")\n continue\n a = float(input(\"Первое число: \"))\n b = float(input(\"Второе число: \"))\n result = operations[choice](a, b)\n print(f\"Результат: {result}\")\n except ValueError as e:\n print(f\"Ошибка: {e}\")\n except Exception as e:\n print(f\"Неизвестная ошибка: {e}\")\nPython калькулятор пример (пример калькулятора на python)
\nТипичные проблемы и решения:
\n- \n
- При вводе букв вместо чисел возникает ValueError. Решение: обернуть преобразование в try/except. \n
- Деление на ноль ломает программу. Решение: явная проверка в функции divide и выброс исключения. \n
- Пользователь может ввести номер операции не из списка. Решение: проверка наличия ключа в словаре. \n
Этот вариант удобен для повторного использования кода и легко расширяется новыми операциями.
\nВариант 1: Простой консольный калькулятор
\nКак сделать базовый калькулятор с выбором операции без функций?
\nЦель: минимальный код для одного вычисления.
\n\nprint(\"1. Сложение\\n2. Вычитание\\n3. Умножение\\n4. Деление\")\nchoice = input(\"Выберите операцию: \")\na = float(input(\"Первое число: \"))\nb = float(input(\"Второе число: \"))\n\nif choice == '1':\n print(a + b)\nelif choice == '2':\n print(a - b)\nelif choice == '3':\n print(a * b)\nelif choice == '4':\n if b != 0:\n print(a / b)\n else:\n print(\"Деление на ноль запрещено\")\nelse:\n print(\"Неверный выбор\")\n\n
Ошибки: при вводе нечислового значения программа упадёт. Если пользователь введёт неверный номер, результат не будет обработан. Решение: добавить обработку исключений и проверку деления на ноль.
\nТакой вариант подходит для обучения основам условных конструкций.
\nВариант 2: Калькулятор с бесконечным циклом
\nКак организовать повторный запуск калькулятора до команды выхода?
\nЦель: многократное выполнение операций без перезапуска программы.
\n\nwhile True:\n print(\"Выберите операцию: + - * / или 'q' для выхода\")\n op = input(\"Операция: \")\n if op.lower() == 'q':\n break\n if op not in ['+', '-', '*', '/']:\n print(\"Неизвестная операция\")\n continue\n a = float(input(\"Число A: \"))\n b = float(input(\"Число B: \"))\n if op == '+':\n print(a + b)\n elif op == '-':\n print(a - b)\n elif op == '*':\n print(a * b)\n elif op == '/':\n if b == 0:\n print(\"Деление на ноль\")\n else:\n print(a / b)\n\n
Потенциальная проблема: бесконечный цикл, если забыть break. Также отсутствует обработка ввода нечисловых значений. Рекомендуется добавить try/except для float.
\nЭтот вариант удобен для работы с последовательностью вычислений без перезапуска.
\nВариант 3: Калькулятор с использованием eval (осторожно)
\nКак вычислить математическое выражение, введённое строкой?
\nЦель: один ввод для всего выражения (например, \"2+3*4\").
\n\nexpr = input(\"Введите выражение: \")\ntry:\n result = eval(expr)\n print(f\"Результат: {result}\")\nexcept Exception as e:\n print(f\"Ошибка: {e}\")\n\nВажное предупреждение:
\nФункция eval выполняет произвольный код Python. Если программа используется в окружении, где ввод может быть небезопасным (например, веб-форма), злоумышленник может выполнить вредоносный код. Используйте eval только для локальных экспериментов. Для безопасного вычисления математических выражений применяйте библиотеку ast.literal_eval или парсеры вроде sympy.
\nДанный подход полезен для быстрого прототипирования, но непригоден для публичных приложений.
\nВариант 4: Графический калькулятор на tkinter
\nКак создать приложение с кнопками для ввода чисел и операций?
\nЦель: пользовательский интерфейс с мышью.
\n\nimport tkinter as tk\n\ndef click(character):\n current = entry.get()\n entry.delete(0, tk.END)\n entry.insert(0, current + str(character))\n\ndef clear():\n entry.delete(0, tk.END)\n\ndef calculate():\n try:\n result = eval(entry.get())\n entry.delete(0, tk.END)\n entry.insert(0, str(result))\n except:\n entry.delete(0, tk.END)\n entry.insert(0, \"Ошибка\")\n\nroot = tk.Tk()\nroot.title(\"Калькулятор\")\nentry = tk.Entry(root, width=30, font=(\"Arial\", 14))\nentry.grid(row=0, column=0, columnspan=4)\n\nbuttons = [\n ('7', 1, 0), ('8', 1, 1), ('9', 1, 2), ('/', 1, 3),\n ('4', 2, 0), ('5', 2, 1), ('6', 2, 2), ('*', 2, 3),\n ('1', 3, 0), ('2', 3, 1), ('3', 3, 2), ('-', 3, 3),\n ('0', 4, 0), ('.', 4, 1), ('C', 4, 2), ('+', 4, 3)\n]\n\nfor (text, row, col) in buttons:\n if text == 'C':\n btn = tk.Button(root, text=text, command=clear, width=5, height=2)\n else:\n btn = tk.Button(root, text=text, command=lambda t=text: click(t), width=5, height=2)\n btn.grid(row=row, column=col)\n\ntk.Button(root, text='=', command=calculate, width=5, height=2).grid(row=5, column=0, columnspan=4)\nroot.mainloop()\n\nПроблемы: использование eval несёт те же риски, что и в консольной версии. Для графического приложения можно реализовать безопасное вычисление вручную. Кроме того, tkinter может быть не предустановлен в некоторых дистрибутивах Linux (установка через python3-tk).
\nГрафический калькулятор даёт наглядное представление и подходит для интеграции в настольные приложения.
\nВариант 5: Калькулятор с аргументами командной строки
\nКак передать числа и операцию через терминал при запуске программы?
\nЦель: автоматизация вычислений в скриптах.
\n\nimport sys\n\nif len(sys.argv) != 4:\n print(\"Использование: python calculator.py <число1> <операция> <число2>\")\n sys.exit(1)\n\ntry:\n a = float(sys.argv[1])\n op = sys.argv[2]\n b = float(sys.argv[3])\n if op == '+':\n print(a + b)\n elif op == '-':\n print(a - b)\n elif op == '*':\n print(a * b)\n elif op == '/':\n if b == 0:\n print(\"Деление на ноль\")\n else:\n print(a / b)\n else:\n print(\"Неизвестная операция\")\nexcept ValueError:\n print(\"Неверный формат чисел\")\n\n
Ошибка: если пользователь не указал все аргументы, программа завершается с сообщением. Можно также использовать библиотеку argparse для более гибкого разбора.
\nТакой калькулятор удобен для интеграции в цепочки конвейеров командной строки.
\nРасширенные примеры калькуляторов на Python
\nВ этом разделе представлены менее распространённые, но полезные реализации калькулятора.
\nПример 1: Калькулятор с поддержкой скобок и приоритетов (не через eval)
\nИспользуется обратная польская запись (алгоритм сортировочной станции).
\n\ndef infix_to_postfix(expression):\n precedence = {'+':1, '-':1, '*':2, '/':2, '(':0}\n output = []\n stack = []\n for token in expression.replace(' ', ''):\n if token.isdigit():\n output.append(token)\n elif token == '(':\n stack.append(token)\n elif token == ')':\n while stack and stack[-1] != '(':\n output.append(stack.pop())\n stack.pop()\n else:\n while stack and precedence.get(stack[-1], 0) >= precedence[token]:\n output.append(stack.pop())\n stack.append(token)\n while stack:\n output.append(stack.pop())\n return ' '.join(output)\n\ndef eval_postfix(expr):\n stack = []\n for token in expr.split():\n if token.isdigit():\n stack.append(float(token))\n else:\n b = stack.pop()\n a = stack.pop()\n if token == '+':\n stack.append(a + b)\n elif token == '-':\n stack.append(a - b)\n elif token == '*':\n stack.append(a * b)\n elif token == '/':\n stack.append(a / b if b != 0 else float('inf'))\n return stack[0]\n\nexpr = \"(3+4)*(5-2)\"\npostfix = infix_to_postfix(expr)\nresult = eval_postfix(postfix)\nprint(f\"Выражение: {expr}\")\nprint(f\"Постфикс: {postfix}\")\nprint(f\"Результат: {result}\")\n\n\nВыражение: (3+4)*(5-2)\nПостфикс: 3 4 + 5 2 - *\nРезультат: 21.0\n\n
Пояснение: данный код разбирает инфиксное выражение с помощью алгоритма сортировочной станции, затем вычисляет постфиксную запись. Это безопаснее eval и поддерживает приоритет операций.
\nПример 2: Калькулятор с историей вычислений
\nСохраняет каждую операцию в список и выводит её по запросу.
\n\nhistory = []\n\ndef add(a, b):\n return a + b\n\ndef sub(a, b):\n return a - b\n\ndef mul(a, b):\n return a * b\n\ndef div(a, b):\n if b == 0:\n return \"Ошибка: деление на ноль\"\n return a / b\n\nops = {'+': add, '-': sub, '*': mul, '/': div}\n\nwhile True:\n print(\"Введите выражение (например, 2 + 3) или 'h' для истории, 'q' для выхода:\")\n inp = input().strip()\n if inp == 'q':\n break\n if inp == 'h':\n for i, entry in enumerate(history, 1):\n print(f\"{i}: {entry}\")\n continue\n parts = inp.split()\n if len(parts) != 3:\n print(\"Формат: число операция число\")\n continue\n try:\n a = float(parts[0])\n op = parts[1]\n b = float(parts[2])\n if op not in ops:\n print(\"Неизвестная операция\")\n continue\n res = ops[op](a, b)\n history.append(f\"{a} {op} {b} = {res}\")\n print(f\"= {res}\")\n except ValueError:\n print(\"Неверные числа\")\n\n\nВведите выражение (например, 2 + 3) или 'h' для истории, 'q' для выхода:\n10 / 3\n= 3.3333333333333335\nВведите выражение (например, 2 + 3) или 'h' для истории, 'q' для выхода:\n2 * 5\n= 10.0\nВведите выражение (например, 2 + 3) или 'h' для истории, 'q' для выхода:\nh\n1: 10.0 / 3.0 = 3.3333333333333335\n2: 2.0 * 5.0 = 10.0\n\n
Такой калькулятор полезен для пошаговых вычислений, когда требуется отследить последовательность операций.
\nПример 3: Калькулятор с сохранением результатов в файл
\nКаждый результат дописывается в текстовый файл.
\n\nimport datetime\n\ndef calculate(a, b, op):\n if op == '+':\n return a + b\n elif op == '-':\n return a - b\n elif op == '*':\n return a * b\n elif op == '/':\n if b == 0:\n return None\n return a / b\n return None\n\nwhile True:\n try:\n a = float(input(\"Число A (или 'exit'): \"))\n except:\n break\n op = input(\"Операция (+ - * /): \")\n b = float(input(\"Число B: \"))\n res = calculate(a, b, op)\n if res is None:\n print(\"Ошибка.\")\n else:\n timestamp = datetime.datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n line = f\"{timestamp}: {a} {op} {b} = {res}\"\n print(line)\n with open(\"history.txt\", \"a\") as f:\n f.write(line + \"\\n\")\n\n\nЧисло A (или 'exit'): 12\nОперация (+ - * /): *\nЧисло B: 3.5\n2025-04-08 14:32:10: 12.0 * 3.5 = 42.0\n\n
При каждом запуске файл history.txt будет пополняться. Подходит для аудита вычислений.
\nПример 4: Калькулятор с использованием словаря lambda-функций
\nКомпактное определение операций через лямбды.
\n\nops = {\n '+': lambda a, b: a + b,\n '-': lambda a, b: a - b,\n '*': lambda a, b: a * b,\n '/': lambda a, b: a / b if b != 0 else float('inf')\n}\n\nwhile True:\n expr = input(\"Введите два числа и операцию через пробел: \")\n if expr == 'q':\n break\n parts = expr.split()\n if len(parts) != 3:\n print(\"Нужно три элемента\")\n continue\n try:\n a, op, b = float(parts[0]), parts[1], float(parts[2])\n if op in ops:\n print(ops[op](a, b))\n else:\n print(\"Нет такой операции\")\n except ValueError:\n print(\"Неверные числа\")\n\n\nВведите два числа и операцию через пробел: 8 / 0\ninf\nВведите два числа и операцию через пробел: 3.14 * 2\n6.28\n\n
Лямбды позволяют сократить код, но их следует использовать для простых функций.
\nПример 5: Безопасный калькулятор с проверкой ввода
\nДопускаются только цифры, точки и знаки операций. Запрещено использование eval.
\n\nimport re\n\ndef safe_calc(expression):\n allowed = re.compile(r'^[0-9+\-*/.()]+$')\n if not allowed.match(expression):\n return \"Запрещённые символы\"\n # Используется словарь для безопасного вычисления без eval\n # Здесь можно применить парсер, например, из примера 1\n # Упрощенно: вычислим через eval (но только для демонстрации, в реальности не стоит)\n try:\n result = eval(expression)\n return result\n except ZeroDivisionError:\n return \"Деление на ноль\"\n except:\n return \"Ошибка вычисления\"\n\nprint(safe_calc(\"2+3*4\"))\nprint(safe_calc(\"2**3\")) # ** не входит в allowed, вернёт ошибку\n\n
\n14\nЗапрещённые символы\n\n
Хотя здесь снова использован eval, основная идея: фильтрация ввода перед передачей. В реальных проектах лучше реализовать полноценный синтаксический анализатор.
\n