Своя викторина: список вопросов, проверка ответов и подсчёт баллов

Практикумобновлено 07.10.20268 мин чтенияесть тренажёр

Викторина на Python — программа, которая задаёт вопросы, сравнивает ответы с правильными и считает баллы. Начнём с версии из 3 вопросов на if, затем перенесём вопросы в список, добавим перемешивание, варианты ответов и словари. Рабочая версия уже в редакторе: запустите и ответьте на 5 вопросов.

Загружаем…

Самая простая викторина на Python

Самая простая версия — это 3 одинаковых блока: вывести вопрос, получить ответ через input(), сравнить его с правильным и прибавить балл. Такой код пишется за 10 минут и сразу работает.

score = 0

answer = input("Сколько будет 7 * 8? ")
if answer == "56":
    score += 1

answer = input("Сколько бит в одном байте? ")
if answer == "8":
    score += 1

answer = input("Какая функция выводит текст? ")
if answer == "print":
    score += 1

print("Баллов:", score)

Переменная score — счётчик баллов. Она создаётся до первого вопроса и увеличивается на 1 после каждого верного ответа. Обратите внимание: ответ сравнивается со строкой «56», а не с числом 56, ведь input всегда возвращает текст. Если написать answer == 56, условие никогда не выполнится, и ошибки при этом не будет — программа просто не начислит балл. Каждый верный ответ приносит ровно 1 балл, а неверный — 0, поэтому итоговая сумма баллов равна количеству правильных ответов.

У этой версии есть очевидный недостаток: для 20 вопросов придётся скопировать блок 20 раз. А если захочется изменить формат вывода, правку нужно будет повторить в каждом блоке. Это верный признак того, что пора заводить список и цикл.

Список вопросов и цикл for

Чтобы не копировать код, вопросы хранят в списке: каждый элемент — пара из текста вопроса и правильного ответа. Цикл for проходит по списку, и блок проверки пишется 1 раз.

questions = [
    ["Сколько будет 7 * 8?", "56"],
    ["Сколько бит в одном байте?", "8"],
    ["Какая функция выводит текст?", "print"],
]
score = 0
for q in questions:
    answer = input(q[0] + " ")
    if answer == q[1]:
        score += 1
print("Баллов:", score, "из", len(questions))

Здесь q[0] — текст вопроса, q[1] — ответ. Функция len(questions) сама считает, сколько вопросов в списке, поэтому строку с результатом не нужно править, когда вопросов станет больше. Теперь, чтобы добавить вопрос, достаточно дописать одну строку в список, а логика программы не меняется. Такое разделение данных и кода — главная идея всего проекта. Если списки пока непривычны, загляните в урок о списках в Python.

Проверка ответа без придирок

Если сравнивать строки напрямую, ответ «Print» или «print » с пробелом засчитан не будет. Чтобы проверка была честной, ответ перед сравнением нормализуют: убирают пробелы, приводят к строчным буквам и заменяют «ё» на «е».

def normalize(text):
    return text.strip().lower().replace("ё", "е")

print(normalize("  Ёлка "))
print(normalize("PYTHON") == "python")
елка
True

Правильные ответы в списке тоже стоит хранить в нормализованном виде — строчными буквами и без «ё». Иногда верных вариантов несколько: «7», «семь». Тогда вторым элементом пары делают список допустимых ответов и проверяют через in: if normalize(answer) in q[1]. Для вопросов с числовым ответом можно сравнивать числа, но только после проверки, что строка действительно состоит из цифр, иначе int() упадёт с ошибкой ValueError. Методы strip и lower описаны в официальной документации Python в разделе о строках. Подробнее о них — в статье про строки в Python.

Баллы, проценты и оценка

Итог викторины удобнее показывать не только числом баллов, но и процентом: процент — это баллы, умноженные на 100 и делённые на число вопросов. Для целого результата используют деление //.

score = 4
total = 5
percent = score * 100 // total
print(percent)
80

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

Процент верныхУсловие в кодеСообщение
90–100percent >= 90Знаток!
70–89percent >= 70Очень неплохо
40–69percent >= 40Есть что повторить
0–39ветка elseПопробуй ещё раз

Условия проверяются сверху вниз через if и elif, поэтому во второй строке не нужно писать «и меньше 90»: если бы процент был 90 или выше, сработала бы первая ветка. Порядок здесь важен — если поставить проверку на 40 первой, все результаты от 40 до 100 получат одну и ту же оценку.

Перемешивание вопросов: random.shuffle

Чтобы при каждом запуске вопросы шли в новом порядке, список перемешивают функцией random.shuffle. Она меняет сам список и ничего не возвращает — это 1 строка без присваивания.

import random

questions = ["вопрос 1", "вопрос 2", "вопрос 3", "вопрос 4"]
random.shuffle(questions)
print(questions)

Классическая ошибка — написать questions = random.shuffle(questions). Функция вернёт None, и в переменной окажется пустое значение вместо списка: следующий цикл упадёт с TypeError. По официальной документации Python shuffle перемешивает «на месте»[1], поэтому присваивать результат не нужно. Если хочется задать только часть вопросов, после перемешивания возьмите срез questions[:5] — первые пять. Баллы после shuffle считаются так же: порядок вопросов на результат не влияет. Другие функции модуля разобраны в статье о модуле random.

Варианты ответов и словари

Если вопрос с вариантами ответа, удобнее хранить его словарём: ключ "text" — текст вопроса, "options" — список вариантов, "answer" — номер правильного. Тогда игрок вводит цифру, а не слово.

quiz = [
    {"text": "Что выведет print(2 ** 3)?", "options": ["6", "8", "9"], "answer": 2},
    {"text": "Сколько бит в байте?", "options": ["4", "8", "16"], "answer": 2},
]
points = 0
for item in quiz:
    print(item["text"])
    for i, option in enumerate(item["options"], start=1):
        print(i, option)
    choice = input("Номер ответа: ")
    if choice == str(item["answer"]):
        points += 1
print("Верных ответов:", points)

Функция enumerate нумерует варианты с единицы, чтобы игроку было привычно. Сравнение идёт строк: ввод «2» сравнивается с str(item["answer"]). Словари делают структуру понятной: через месяц не придётся вспоминать, что означает q[2], ведь в коде написано item["answer"]. В такой словарь легко добавить новые поля — подсказку, тему или стоимость вопроса в баллах. О ключах и значениях подробнее рассказано в уроке о словарях Python.

Как придумать хорошие вопросы

Хороший вопрос имеет 1 однозначный ответ, который можно проверить сравнением строк. «Что такое цикл?» для программы не годится, а «Сколько раз выполнится range(4)?» — подходит.

Викторина на Python — не только упражнение в программировании, но и способ учить любой предмет. Исследование Roediger и Karpicke показало, что самопроверка закрепляет материал лучше, чем повторное чтение[2]. Поэтому вопросы по истории, английским словам или таблице умножения, собранные в собственную программу, работают как карточки для запоминания. Начните с 5–7 вопросов по одной теме и добавляйте по несколько штук после каждого урока. Если программа подсказывает правильный ответ после ошибки, повторный прогон через день покажет, что запомнилось.

Викторина на Python как учебный проект

Викторина на Python — проект, который покрывает 5 тем школьного курса сразу: переменные, ввод, ветвления, циклы и списки. Поэтому её удобно делать как итоговую работу после первых уроков программирования.

По федеральной образовательной программе основного общего образования в 8 классе изучают ветвления, циклы и обработку строк, а в 9 классе — одномерные массивы, которым в Python соответствуют списки. Викторина использует всё это одновременно. На ОГЭ по информатике, по материалам ФИПИ, программу в задании 16 можно писать на Python, и привычка аккуратно обрабатывать ввод там тоже пригодится. Хорошая идея для класса — каждый ученик пишет по 3 вопроса, а потом их собирают в один общий список. Баллы считает программа, поэтому спорить о результате не приходится, а каждый автор видит, насколько трудными оказались его вопросы для других.

Когда текстовая викторина не подходит

Текстовая версия не подходит, когда ответ нельзя свести к короткой строке или цифре. Вот 4 таких случая.

  • Ответ — развёрнутое объяснение. Сравнение строк не оценит текст из 2–3 предложений, нужен живой проверяющий.
  • Ребёнку 7–8 лет. Набор ответов утомляет; проще собрать викторину из блоков, как в статье о викторине в Scratch.
  • Нужны картинки и звук. Программа выводит только текст в 1 окне.
  • Вопросов больше 100. Держать их в коде неудобно; лучше научиться читать вопросы из файла.

«Чтобы сделать викторину, нужен специальный конструктор или платный сервис». Это миф: хватает стандартного Python — списков, словарей, input и модуля random. Никаких сторонних библиотек не требуется.

«Если перемешать вопросы, проверка ответов собьётся». Это не подтверждается: shuffle перемещает пары целиком, и правильный ответ остаётся рядом со своим вопросом.

Чего делать нельзя

Нельзя выпускать викторину, не пройдя её самому хотя бы 2 раза: опечатка в правильном ответе делает вопрос нерешаемым. Ещё 6 правил:

  • Нельзя присваивать результат shuffle — функция вернёт None, и список пропадёт.
  • Не стоит сравнивать ответ с числом без преобразования: input возвращает строку.
  • Не следует хранить правильные ответы с заглавными буквами, если ввод приводится к строчным.
  • Не стоит создавать счётчик внутри цикла: он будет обнуляться перед каждым вопросом.
  • Нельзя называть переменную list или input: вы перекроете встроенные функции Python.
  • Не допускается задавать вопросы с двумя верными ответами, если программа принимает только один.

Имена переменных в примерах записаны по правилам PEP 8[3] — строчными буквами, слова через подчёркивание.

Источники

[1] The Python Tutorial (официальная документация Python 3). Python Software Foundation.

[2] Roediger H. L., Karpicke J. D. Test-enhanced learning: Taking memory tests improves long-term retention // Psychological Science. 2006. Vol. 17, № 3. P. 249–255.

[3] van Rossum G., Warsaw B., Coghlan N. PEP 8 — Style Guide for Python Code. Python Software Foundation, 2001.

Вопросы и ответы

Сколько вопросов должно быть в викторине?

Для первой версии хватит 5. Когда программа заработает, добавляйте сколько угодно: код от этого не меняется.

Как не задавать один вопрос дважды?

Перемешайте список и пройдите его циклом for — каждый элемент встретится ровно один раз. Функция choice в цикле может выбрать один и тот же элемент повторно.

Можно ли ограничить время на ответ?

Модуль time позволяет засечь, сколько секунд прошло между вопросом и ответом, и не начислить балл за слишком долгий ответ. Прервать уже начатый ввод так просто не получится.

Как показать ошибки в конце?

Заведите пустой список и добавляйте в него вопрос через append при неверном ответе. После цикла выведите этот список.

Чем викторина на Python отличается от квиза на этом сайте?

Квиз на сайте — готовый тренажёр с вариантами ответа. Здесь же вы пишете похожую программу сами и решаете, какие вопросы задавать.

Как сделать вопросы разной стоимости?

Добавьте в словарь вопроса поле "cost" и прибавляйте к счёту его значение вместо единицы. Сложные вопросы тогда принесут больше очков.