2025, Nov 20 18:01

Повторный запрос ввода в интерактивных скриптах Python: вложенный цикл вместо пропуска элемента

Разбираем типичную ошибку в интерактивных скриптах Python: пропуск элемента после неверного ввода. Показываем решение с вложенным циклом и безопасным выходом.

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

Проблема

Нужно собрать пять оценок, каждая привязана к конкретному разведению. Разрешён только заданный набор строк, а ввод q должен завершать сеанс и показывать уже собранные данные. Текущий подход после некорректного ввода сразу переходит к следующему разведению вместо того, чтобы повторно спросить текущее.

Проблемный код

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

series = ["1:16", "1:32", "1:64", "1:128", "1:256"]
permitted = ["+", "++-", "-", "+-", "-a", "A"]
ledger = {}

for ratio in series:
    mark = input("Enter score: ")
    try:
        if mark in permitted:
            ledger[ratio] = mark
        elif mark == "q":
            print("Done!")
            break
        else:
            print("Not a valid score!")
    except TypeError:
        print("Invalid input! Try again")
        break
print(ledger)

Почему это не работает

После неверного значения код выводит сообщение и тут же переходит к следующему разведению во внешнем цикле. Механизма, чтобы повторить запрос для того же разведения, нет. Кроме того, обработка исключений здесь бесполезна, потому что показанная логика не вызывает TypeError: чтение ввода и проверка принадлежности элементу списка не приведут к такому исключению. В итоге некорректные записи оставляют тихие «дыры» в соответствиях между разведениями и оценками.

Решение

Прямолинейное исправление — вложенный цикл. Для каждого разведения повторяйте запрос, пока не будет введена допустимая оценка или не придёт q. Это гарантирует один из двух исходов для каждого элемента: оценка записана либо выполнение немедленно остановлено.

series = ["1:16", "1:32", "1:64", "1:128", "1:256"]
permitted = ["+", "++-", "-", "+-", "-a", "A"]
ledger = {}

for ratio in series:
    while ratio not in ledger:
        mark = input("Enter score: ")
        if mark in permitted:
            ledger[ratio] = mark
        elif mark == "q":
            print("Done!")
            exit()
        else:
            print("Not a valid score! Try again")

print(ledger)

Если вы не хотите завершать процесс целиком через exit(), используйте флаг: выйдите из внутреннего цикла, а затем остановите внешний.

series = ["1:16", "1:32", "1:64", "1:128", "1:256"]
permitted = ["+", "++-", "-", "+-", "-a", "A"]
ledger = {}

stop_now = False

for ratio in series:
    while ratio not in ledger:
        mark = input("Enter score: ")
        if mark in permitted:
            ledger[ratio] = mark
        elif mark == "q":
            print("Done!")
            stop_now = True
            break
        else:
            print("Not a valid score! Try again")
    if stop_now:
        break

print(ledger)

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

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

Выводы

Привязывайте проверку к обрабатываемому элементу. Используйте вложенный цикл, чтобы повторять запрос, пока ввод не будет допустим или пока не поступит команда выхода. Не прибегайте к обработке исключений там, где исключений не ожидается: это создаёт шум, не повышая корректность. Выберите ясную стратегию выхода: либо немедленно завершайте работу, либо ставьте флаг для аккуратного прекращения. С такими поправками каждое разведение гарантированно получает оценку, а при необходимости сессия останавливается по задумке.