Диалог с пользователем через командную строку: программа Yes/No на Python

Диалоговые программы используются везде, примером может служить любое приложение на вашем компьютере (браузер, видеоплееры, текстовые редакторы и т. д.). Диалог Yes/No — это простой пример диалоговой программы, работающей с командной строкой.

Что такое диалоговая программа и зачем она нужна

Программа, в которой предусмотрено взаимодействие с пользователем, называется диалоговой (интерактивной).

Ввод текста, нажатия на кнопки, загрузка файлов — всё это способы взаимодействия пользователя с приложением.

Диалог между программой и пользователем — это важная часть любого проекта. Если программа работает с одними строго определенными данными, она не несёт какого-либо практического смысла.

Диалоговая программа Yes/No на Python

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

Суть такой программы проста: пользователь отвечает на вопросы, вводя в консоль Yes – да, или No – нет. Не стоит думать, что сейчас актуально взаимодействовать с программой только через графический интерфейс, командная строка также используется.

Например, в операционной системе Linux часто устанавливают программы через командную строку. Система может приостановить процесс и спросить пользователя, желает ли он продолжить установку «Do you want to continue [Y/n]?», для подтверждения он должен ввести Y, иначе N.

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

Консольный диалог Yes/No особенно актуален, потому что не требует реализовывать графический интерфейс, который может быть бесполезен для выполнения определённых задач.

Реализация функции диалога Yes/No на Python

Написать консольную диалоговую программу на Python очень просто, однако нужно учесть и продумать некоторые нюансы, такие как неверный ввод от пользователя. Yes/no легко можно заменить на Да/нет, но давайте следовать общепринятым стандартам и использовать английский язык.

Объявление функции

Поместим всю логику диалоговой программы в отдельную функцию, которую объявим так:

def yes_no_dialog(question, default_answer="yes"):

Здесь аргументы означают следующее:

  • question – это вопрос, который выводится в командную строку, и на который пользователь должен дать ответ «yes» или «no».
  • default_ answer – это необязательный параметр, который будет использоваться в том случае, если пользователь не введет ответ, а просто нажмет Enter.

Начальные настройки

Предположим, что пользователь может вводить не только «yes», но и «y» или «ye». Обработка каждого вариант с помощью условных операторов if — else нецелесообразна и требует много лишнего кода. Поэтому поместим все варианты ответа в словарь:

answers = {"yes":1, "y":1, "ye":1,
           "no":0, "n":0}

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

if default_answer == None:
    # Если ответ по умолчанию не определен
    tip = " [y/n] " # выводим обе буквы в нижнем регистре
elif default_answer == "yes":
    # Если ответ по умолчанию "yes"
    tip = " [Y/n] " # Выделяем Y
elif default_answer == "no":
    # Если ответ по умолчанию "no"
    tip = " [y/N] "
else:
    raise ValueError(f'Неверное значение: {default_answer = }')

При вводе аргумента default_answer тоже можно допустить ошибку, поэтому в блоке else мы возбуждаем исключение, которое указывает на неверный ввод.

Основной цикл

Необходимо продумать следующие ситуации, когда пользователь:

  • Ничего не вводит, но определен default_answer.
  • Вводит верный ответ.
  • Вводит неверный ответ.

Для реализации лучше использовать бесконечный цикл. Сначала необходимо вывести вопрос и подсказку, а затем получить ввод пользователя:

while True:
    print(question + tip + ": ", end="")
    user_answer = input().lower() # приводим к нижнему регистру

Подробнее про ввод и вывод данных можно почитать здесь.

Теперь ввод необходимо обработать так, чтобы при правильном вводе происходил выход из цикла, а при неправильном цикл начинался заново:

# Если default_answer определен, а пользователь ничего не ввёл
if default_answer is not None and user_answer == '':
    # Выходим из функции, возвращая значение, соответствующее default_answer
    return answers[default_answer]
# Если пользователь ввел верный ответ
elif user_answer in answers:
    return answers[user_answer]
# Если ответ неверен, выводим сообщение и продолжаем цикл
else:
    print("Пожалуйста, введите yes/y или no/n\n")

Полный код функции

Соединив все вместе, получаем готовую к использованию функцию для диалога с пользователем:

def yes_no_dialog(question, default_answer="yes"):
    answers = {"yes":1, "y":1, "ye":1,
        "no":0, "n":0}
    if default_answer == None:
        tip = " [y/n] "
    elif default_answer == "yes":
        tip = " [Y/n] "
    elif default_answer == "no":
        tip = " [y/N] "
    else:
        raise ValueError(f'Неверное значение: {default_answer = }')
    while True:
        print(question + tip + ": ", end="")
        user_answer = input().lower()
        if default_answer is not None and user_answer == '':
            return answers[default_answer]
        elif user_answer in answers:
            return answers[user_answer]
        else:
            print("Пожалуйста, введите yes/y или no/n\n")

Пример программы

Предположим, что функция получает несколько вопросов из файла, результаты ответов записываются в другой файл, тогда код программы будет выглядеть так:

a = open("qst.txt", "r", encoding="utf-8") # открываем файл для чтения
results = []
for line in a: # читаем файл построчно
    # Для каждой строки вызываем нашу функцию и помещаем возвращаемое
    # ею значение в список result
    results.append(yes_no_dialog(line.strip()))
a.close()
b = open("results.txt", "w") # Открываем файл для записи
for elem in results:
    # Записываем каждый элемент списка в файл через пробел
    b.write(str(elem) + " ")
b.close()

С помощью метода строк strip удалим лишние символы.

Перед запуском программы на Python надо не забыть подготовить файл с вопросами qst.txt такого вида:

Первый вопрос
Второй вопрос
Третий вопрос

Чтобы русские буквы корректно отображались — правильно указываем кодировку при открытии файла. В моём случае это encoding="utf-8".

Результатом выполнения будет следующее:

Первый вопрос [Y/n] : Y
Второй вопрос [Y/n] : no
Третий вопрос [Y/n] : yes

Содержимое файла результата будет следующим:

1 0 1