2025, Sep 26 21:17

Почему интерактивный калькулятор на Python перезапускается и не показывает результат и как это исправить

Почему интерактивный калькулятор на Python перезапускается и не выводит ответ: return вместо print, проверка операции, упрощение логики и рабочее решение.

Интерактивный калькулятор на Python постоянно перезапускается и не показывает результат: что происходит и как это исправить

Создание небольшого интерактивного калькулятора — отличный способ освоить ввод/вывод и управляющие конструкции Python. Но распространённая ошибка — ожидать, что функция покажет результат лишь потому, что она возвращает значение. Если ваша программа принимает все данные, а затем перезапускается, не выводя итоговый ответ, скорее всего, вы возвращаете результат вместо того, чтобы его печатать. Кроме того, есть несколько моментов в управлении потоком выполнения и форматировании, которые могут скрывать ожидаемое поведение.

Проблемный пример

Следующий фрагмент демонстрирует проблему. Он считывает числа и операцию, подготавливает вертикальное представление выражения, а затем преждевременно завершает работу до того, как что‑либо появляется в консоли.

def calc_runner():
    while True:
        try:
            lhs = float(input('Add 1st number: '))
            rhs = float(input('Add 2nd number: '))
        except ValueError:
            print('Invalid input. Please enter a number')
            continue
        ops_set = set(['+', '-', '/', '*'])
        try:
            op_choice = input('Please choose operation from [+, -, *, /]: ')
        except op_choice not in ops_set:
            print(f'Function must contain mathetmatical operation values only')
            continue
        header_line = ""
        op_line = ""
        dash_line = ""
        out_line = ""
        if op_choice == '+':
            result_val = lhs + rhs
        elif op_choice == '-':
            result_val = lhs - rhs
        elif op_choice == '*':
            result_val = lhs * rhs
        elif op_choice == '/':
            if rhs == 0:
                print(f'Division by 0 not possible')
                continue
            else:
                result_val = lhs / rhs
        s_lhs = str(lhs)
        s_rhs = str(rhs)
        s_out = str(result_val)
        col_width = max(len(s_lhs), len(s_rhs)) + 2
        top_line = s_lhs.rjust(col_width)
        bottom_line = op_choice + s_rhs.rjust(col_width - 1)
        sep_line = '-' * col_width
        res_line = s_out.rjust(col_width)
        header_line += top_line
        op_line += bottom_line
        dash_line += sep_line
        out_line += res_line
        display_block = f'{header_line}\n{op_line}\n{dash_line}\n{out_line}'
        return display_block
        exit_choice = input('Quit Program? Y/N: ')
        if exit_choice == 'Y' or exit_choice == 'y':
            break
calc_runner()

Почему программа не показывает результат

Корневая причина — использование return вместо print для финального вывода. Оператор return возвращает значение вызывающему коду и сразу завершает функцию; он ничего не отображает в терминале. Поскольку функция выходит до печати или запроса на завершение, на экран ничего не выводится, а код после return не выполняется.

Есть и вторая логическая ошибка при проверке операции. Блок except используется там, где нужен обычный условный оператор. Клауза except срабатывает только при возникновении исключения, а не при провале проверки принадлежности. Чтобы проверять ввод на соответствие набору допустимых символов, используйте условие if и продолжайте цикл (continue), если ввод неверный.

Несколько переменных для форматирования заполняются через +=, хотя значения не накапливаются. Это размывает замысел и создаёт лишний шум. Проще один раз сформировать нужные строки и использовать их напрямую.

Есть и небольшой изъян в управлении потоком после проверки деления на ноль. После выполнения continue код в этой ветке дальше не выполняется, поэтому else не нужен.

Наконец, запрос на выход сравнивает два варианта явно. Нормализация ввода с помощью lower() упрощает условие без изменения поведения.

Исправление и улучшенная версия

В исправленном варианте вычисленный блок печатается, операция проверяется через if, убраны лишние присваивания, упрощена ветка деления и упорядочена логика выхода. Общее поведение осталось прежним, но теперь результат корректно отображается.

def calc_runner():
    while True:
        try:
            lhs = float(input('Add 1st number: '))
            rhs = float(input('Add 2nd number: '))
        except ValueError:
            print('Invalid input. Please enter a number')
            continue
        ops_set = {'+', '-', '/', '*'}
        op_choice = input('Please choose operation from [+, -, *, /]: ')
        if op_choice not in ops_set:
            print(f'Function must contain mathematical operation values only')
            continue
        if op_choice == '+':
            result_val = lhs + rhs
        elif op_choice == '-':
            result_val = lhs - rhs
        elif op_choice == '*':
            result_val = lhs * rhs
        elif op_choice == '/':
            if rhs == 0:
                print(f'Division by 0 not possible')
                continue
            result_val = lhs / rhs
        s_lhs = str(lhs)
        s_rhs = str(rhs)
        s_out = str(result_val)
        col_width = max(len(s_lhs), len(s_rhs)) + 2
        top_line = s_lhs.rjust(col_width)
        bottom_line = op_choice + s_rhs.rjust(col_width - 1)
        sep_line = '-' * col_width
        res_line = s_out.rjust(col_width)
        display_block = f'{top_line}\n{bottom_line}\n{sep_line}\n{res_line}'
        print(display_block)
        exit_choice = input('Quit Program? Y/N: ')
        if exit_choice.lower() == 'y':
            break
calc_runner()

Почему это важно

Понимание различия между возвратом данных и выводом в stdout — базовый навык в Python. Он влияет на структуру функций, тестирование и подачу результатов в консольных утилитах. Чёткая проверка ввода предотвращает запутанный поток выполнения, а простое форматирование строк и упрощённые ветви делают код понятнее, удобнее для отладки и расширения. Небольшие улучшения вроде нормализации пользовательского ввода сокращают дублирование и устраняют скрытые ошибки.

Выводы и практические советы

Если нужно что‑то показать в терминале, вызывайте print там, где пользователь ждёт отклика. Оставьте return для передачи значений между функциями. Проверяйте пользовательский ввод обычными условиями, а не обработчиками исключений — используйте их только для реальных ошибок, например ValueError при преобразовании в float. Избегайте лишних переменных и ненужных блоков else после continue. Делайте логику выхода из цикла предсказуемой: нормализуйте ответы пользователя перед сравнением.

Статья основана на вопросе с StackOverflow от new_coder и ответе от Aadvik.