Глава 2. Числа и вычисления: операторы и расчёт показателей
Задача главы: научиться считать метрики успеваемости — прирост, средний балл, проценты, распределение по аудиториям — и проверять их по порогам и сложным критериям отбора.
2.1 Математические операторы: расчёт метрик
Зачем это нужно. Почти любой показатель в отчёте — это арифметика над колонками выгрузки: прирост баллов между диагностиками, средний балл группы, доля выполненных заданий. Операторы Python повторяют школьную математику, но с одним важным отличием в делении.
⚠️ Подводный камень
Оператор / всегда возвращает float — даже когда делится нацело. Traceback не появится, ошибка тихая: в отчёт просто уйдёт «Сдали 25.0 человек».
| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
| — (тихая ошибка) | «Результат / — всегда float» | Делили целое на целое и ждали целое. Для штучных величин нужен оператор целочисленного деления // (раздел 2.3), для вывода — форматирование :.0f. |
Правильный паттерн
Пояснение логики: оператор выбирается по смыслу показателя. Штучные объекты — люди, аудитории, комплекты бланков — считаются через //; средние, доли и проценты остаются float. Подробно // разбирается в 2.3.
2.2 Округление: round() и «хвостатые» дроби
Зачем это нужно. Деление регулярно даёт длинную дробь: 83 / 3 = 27.666666666666668. В отчёт такое не поставишь — показатели округляют до одного-двух знаков.
Второй аргумент round() — сколько знаков оставить после запятой. Если его не указать, число округлится до целого.
⚠️ Подводный камень
Python округляет не так, как учили в школе. Здесь работает «банковское округление» — к ближайшему чётному, если дробная часть ровно 0.5.
| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
| — (тихая ошибка) | «Половина округляется к ближайшему чётному» | Не баг, а стандарт: при суммировании тысяч показателей такое округление не завышает итог систематически. Но если методика требует школьного правила «0.5 всегда вверх», round() не подходит. |
Вторая ловушка того же семейства — дробные числа хранятся приблизительно, поэтому round() иногда «промахивается» в последнем знаке:
Правильный паттерн
Округляйте один раз, на выходе, а не на каждом промежуточном шаге — иначе погрешность накапливается. Для вывода удобнее вообще не звать round(), а форматировать прямо в f-строке:
Пояснение логики: :.2f округляет только представление числа при выводе, сама переменная остаётся точной и годится для дальнейших расчётов. Это тот же приём, что в главе 1 с процентом выполнения.
2.3 Деление нацело // и остаток %
Зачем это нужно. Эти два оператора выглядят академической экзотикой ровно до первой организационной задачи: рассадить учеников по аудиториям ППЭ, разложить бланки по комплектам, раздать чётные и нечётные варианты.
// — сколько получилось целых объектов
Отбрасывает дробную часть и отвечает на вопрос «сколько полных штук поместилось».
% — что осталось сверх целых
Возвращает остаток. Нужен для «неукомплектованного хвоста» и для циклического распределения.
Реальное количество аудиторий считается через оба оператора сразу:
Скобка (1 if leftover_students else 0) читается слева направо: «прибавить 1, если остаток есть, иначе 0». Это условие в одну строку — целиком разберём его в главе Условия, здесь достаточно запомнить готовую формулу «полные штуки плюс неполный хвост».
⚠️ Подводный камень
Делитель, пришедший из выгрузки, может оказаться нулём — например, в классе не зарегистрировано ни одного участника.
Traceback (most recent call last): File "report.py", line 2, in <module> average_score = 450 / students_countZeroDivisionError: division by zero| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
ZeroDivisionError | «Делить на ноль не определено» | В знаменателе оказался 0: пустая группа, никто не явился, колонка не заполнена. Проверяйте делитель до расчёта — полноценно это решается в главе про условия. |
2.4 Операторы сравнения: проверка порогов
Зачем это нужно. Каждый критерий в отчёте — «сдал / не сдал», «выше среднего», «высокобалльник» — это сравнение с порогом. Результат сравнения всегда bool: True или False.
| Оператор | Значение | Пример из аналитики |
|---|---|---|
== | равно | grade == 5 — отметка ровно «пять» |
!= | не равно | status != 'absent' — ученик не отсутствовал |
> / < | строго больше / меньше | score > 24 — балл строго выше порога |
>= / <= | больше или равно / меньше или равно | score >= 80 — от 80 и выше, высокобалльник |
Отдельная приятная особенность Python: двойные неравенства пишутся так же, как в математике.
⚠️ Подводный камень
Порог «не ниже 36» — это >=, а не >. Ошибка в одном символе отправляет в неуспевающие всех, кто набрал ровно проходной балл: на большой выгрузке это десятки человек, и заметить это по итоговой цифре почти невозможно.
Вторая частая ловушка — сравнение балла, который забыли привести к числу после input():
Traceback (most recent call last): File "report.py", line 2, in <module> print(score > 36)TypeError: '>' not supported between instances of 'str' and 'int'| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
TypeError | «Не знаю, как сравнить текст с числом» | Забыли int() вокруг input(). Правило главы 1 работает и здесь: приводите тип в момент ввода. |
Правильный паттерн
Пояснение логики: приведение типа стоит в момент ввода, поэтому сравнение работает с числами. Порог живёт в отдельной переменной — если методика поменяет проходной балл, правка будет в одной строке. Результат сравнения сохранён в is_passed с говорящим именем: такую переменную дальше можно и напечатать, и передать в расчёт.
2.5 Логические операторы: and, or, not
Зачем это нужно. Реальные критерии почти никогда не состоят из одного условия: медаль, грант, допуск к сессии — это связки из нескольких порогов.
and — строгий отбор: нужны все условия сразу
or — мягкий отбор: достаточно любого условия
not — инверсия: переворачивает значение
⚠️ Подводный камень
and «сильнее» or — он вычисляется первым, как умножение перед сложением. Без скобок смысл критерия меняется незаметно:
| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
| — (тихая ошибка) | «Сначала связываю and, потом or» | Условие прочиталось как is_olympiad_winner or (ege_math > 80 and ege_rus > 90) — совсем не то, что задумано. Ставьте скобки всегда, когда в критерии есть и and, и or. |
Правильный паттерн
Пояснение логики: скобки фиксируют порядок и заодно делают критерий читаемым — коллега поймёт его без запуска кода. Длинный критерий лучше сохранять в переменную с говорящим именем (is_grant_eligible, is_allowed), а не встраивать прямо в print().
2.6 Мини-словарик ошибок второй главы
| Ошибка | Что значит для Python | Человеческий перевод |
|---|---|---|
ZeroDivisionError | «Деление на ноль не определено» | В знаменателе 0: пустая группа или незаполненная колонка выгрузки. |
TypeError | «> не работает между str и int» | Сравниваете результат input() с числом. Оберните ввод в int(). |
SyntaxError | «Не понимаю структуру строки» | Написали if grade = 5:. Одинарное = — присваивание, сравнение всегда ==. |
| — (тихая ошибка) | «and вычисляется раньше or» | Смешали and и or без скобок — критерий отработал не так, как задумано. |
| — (тихая ошибка) | «Половина округляется к чётному» | round(2.5) даёт 2. Помните про банковское округление в методиках расчёта. |
Самый частый случай целиком. Сам оператор if разбирается в главе Условия, но корень ошибки — здесь, в разделе 2.4: одинарное = присваивает значение, а сравнивает всегда двойное ==.
File "report.py", line 2 if grade = 5: ^^^^^^^^^SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?Мини-кейс: экспресс-проверка претендента на медаль
Задача: принять баллы ЕГЭ по трём предметам, посчитать сумму и средний балл и проверить условие медали — не менее 70 баллов по каждому предмету.
Пример работы при вводе Иванова Анна, 88, 70, 91:
--- ЭКСПРЕСС-ПРОВЕРКА ---Ученик: Иванова АннаРусский: 88 | Математика: 70 | Информатика: 91Сумма баллов: 249Средний балл: 83.0Медаль подтверждена (не ниже 70 по всем): TrueЧто получилось: порог вынесен в переменную min_required — если методика изменится, правку нужно внести в одном месте, а не в трёх сравнениях. Использовано >=, поэтому ученик с ровно 70 баллами по математике медаль сохранил. Средний балл не округлялся заранее: round() не понадобился, форматирование :.1f сделало всё на выводе.
Чек-лист главы
- Помню, что
/всегда возвращаетfloat, даже при делении нацело - Округляю показатели один раз, на выводе, и знаю про банковское округление в
round() - Использую
//для подсчёта целых объектов (аудитории, комплекты) и%для остатка и чередования вариантов - Различаю
>и>=при проверке проходного порога - Понимаю, что сравнение возвращает
bool, и умею писать двойные неравенства80 <= score <= 100 - Собираю сложные критерии через
and/or/notи ставлю скобки при их смешивании - Узнаю
ZeroDivisionErrorиSyntaxErrorпри=вместо== - Выношу пороги и длинные критерии в переменные с говорящими именами
Дальше: Строки и f-строки