Условия и циклы
читаем поток управления
Что это
Поток управления — это порядок, в котором выполняются строки. По умолчанию сверху вниз, но условия и циклы его меняют: какие-то строки пропускаются, какие-то повторяются.
Чтобы прочитать такой код, надо уметь отвечать на один вопрос: при каких данных выполнится эта строка? Остальное прикладывается.
Как выглядит в коде
orders = [
{"id": 1, "status": "paid", "total": 250},
{"id": 2, "status": "pending", "total": 0},
{"id": 3, "status": "paid", "total": 90},
]
total = 0
for order in orders:
if order["status"] != "paid":
continue
if order["total"] <= 0:
print(f"заказ {order['id']}: оплачен, но сумма нулевая")
continue
total += order["total"]
print("итого:", total)Вывод:
итого: 340Как это читать
Отступ — это область действия. Всё, что сдвинуто вправо относительно
for или if, относится к нему. В Python отступ не оформление, а синтаксис:
сдвинул строку — изменил смысл программы.
continue означает «пропустить остаток и взять следующий элемент». Две
такие строки в примере — это фильтры: заказы не оплаченные и с нулевой суммой
до сложения не доходят.
break означает «выйти из цикла совсем». Путать их — частая ошибка при
чтении: continue пропускает один шаг, break прекращает перебор.
else у цикла — редкая конструкция, но встречается. Выполняется, если
цикл завершился без break.
Списковые включения
Тот же смысл можно записать одной строкой:
paid = [o["total"] for o in orders if o["status"] == "paid"]
print(sum(paid)) # 340Читается справа налево по смыслу: взять o из orders, где статус paid,
и собрать из них o["total"]. ИИ пишет такие конструкции охотно — они
короткие, но при двух-трёх условиях становятся нечитаемыми.
Тернарное выражение
status = "оплачен" if order["total"] > 0 else "ожидает"Читается так: status равно "оплачен", если условие верно, иначе
"ожидает". Та же конструкция в JavaScript и Dart пишется иначе:
const status = order.total > 0 ? "оплачен" : "ожидает";Знак ? перед первым вариантом, : перед вторым — это одно и то же, просто
другой синтаксис.
Как сказать ИИ
При каких данных выполнится строка 14? Назови конкретный
пример входных данных, при которых мы до неё дойдём.Этот цикл может не выполниться ни разу? При каких данных?Второй вопрос важнее, чем кажется. Цикл по пустому списку просто ничего не делает — молча, без ошибки. Если дальше код рассчитывает, что в переменной что-то накопилось, он получит ноль или пустоту.
На что смотреть
Глубокая вложенность. Три и больше уровня if внутри for внутри if —
такой код трудно читать и легко сломать. Признак, что часть условий можно
вынести в ранний continue или в отдельную функцию.
Цикл, который может не выполниться. Пустой список, пустой ответ API — и весь блок пропущен. Проверь, что дальше по коду это учтено.
Изменение списка во время перебора. Удаление элементов из того же списка,
по которому идёт for, даёт пропущенные элементы. Выглядит безобидно,
работает неправильно.
Условие, которое всегда истинно или всегда ложно. Бывает после правок:
if status != "paid" or status != "pending" — такое условие верно всегда.
Чтобы заметить, достаточно подставить любое значение.
Шпаргалка
Отступ в Python — синтаксис, а не оформление.
continue— пропустить шаг,break— выйти из цикла.Списковое включение читается как цикл: взять, отфильтровать, собрать.
Главный вопрос: при каких данных выполнится эта строка?
Второй вопрос: может ли цикл не выполниться ни разу?
Не меняй список, пока идёшь по нему циклом.